Add libunwindstack support for Mips and Mips64
This patch requires v3.18 kernel or above, because v3.10 kernel has a bug (as of 8/1/2017) in the ptrace(GETREGSET) function for mips and mips64. Change-Id: I004c1fa190193eebe1c84440b366289122a6bd8a Signed-off-by: Douglas Leung <douglas.leung@mips.com> Signed-off-by: Dejan Jovicevic <dejan.jovicevic@mips.com>
This commit is contained in:
parent
84de4c0a89
commit
61b1a1ae77
23 changed files with 1256 additions and 12 deletions
|
@ -64,6 +64,8 @@ cc_library {
|
|||
"RegsArm64.cpp",
|
||||
"RegsX86.cpp",
|
||||
"RegsX86_64.cpp",
|
||||
"RegsMips.cpp",
|
||||
"RegsMips64.cpp",
|
||||
"Unwinder.cpp",
|
||||
"Symbols.cpp",
|
||||
],
|
||||
|
@ -86,6 +88,12 @@ cc_library {
|
|||
x86_64: {
|
||||
srcs: ["AsmGetRegsX86_64.S"],
|
||||
},
|
||||
mips: {
|
||||
srcs: ["AsmGetRegsMips.S"],
|
||||
},
|
||||
mips64: {
|
||||
srcs: ["AsmGetRegsMips64.S"],
|
||||
},
|
||||
},
|
||||
|
||||
shared_libs: [
|
||||
|
|
80
libunwindstack/AsmGetRegsMips.S
Normal file
80
libunwindstack/AsmGetRegsMips.S
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
.text
|
||||
.type AsmGetRegs, %function
|
||||
.globl AsmGetRegs
|
||||
.ent AsmGetRegs
|
||||
.balign 16
|
||||
AsmGetRegs:
|
||||
.cfi_startproc
|
||||
.cfi_def_cfa $sp, 0
|
||||
.set push
|
||||
.set noreorder
|
||||
.cpload $t9
|
||||
sw $zero, 0($a0)
|
||||
.set noat
|
||||
sw $at, 4($a0)
|
||||
.set at
|
||||
sw $v0, 8($a0)
|
||||
sw $v1, 12($a0)
|
||||
sw $a0, 16($a0)
|
||||
sw $a1, 20($a0)
|
||||
sw $a2, 24($a0)
|
||||
sw $a3, 28($a0)
|
||||
sw $t0, 32($a0)
|
||||
sw $t1, 36($a0)
|
||||
sw $t2, 40($a0)
|
||||
sw $t3, 44($a0)
|
||||
sw $t4, 48($a0)
|
||||
sw $t5, 52($a0)
|
||||
sw $t6, 56($a0)
|
||||
sw $t7, 60($a0)
|
||||
sw $s0, 64($a0)
|
||||
sw $s1, 68($a0)
|
||||
sw $s2, 72($a0)
|
||||
sw $s3, 76($a0)
|
||||
sw $s4, 80($a0)
|
||||
sw $s5, 84($a0)
|
||||
sw $s6, 88($a0)
|
||||
sw $s7, 92($a0)
|
||||
sw $t8, 96($a0)
|
||||
sw $t9, 100($a0)
|
||||
sw $k0, 104($a0)
|
||||
sw $k1, 108($a0)
|
||||
sw $gp, 112($a0)
|
||||
sw $sp, 116($a0)
|
||||
sw $s8, 120($a0)
|
||||
sw $ra, 124($a0)
|
||||
jalr $zero, $ra
|
||||
sw $ra, 128($a0) // set PC to the calling function
|
||||
|
||||
.set pop
|
||||
.cfi_endproc
|
||||
.size AsmGetRegs, .-AsmGetRegs
|
||||
.end AsmGetRegs
|
80
libunwindstack/AsmGetRegsMips64.S
Normal file
80
libunwindstack/AsmGetRegsMips64.S
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
.text
|
||||
.type AsmGetRegs, %function
|
||||
.globl AsmGetRegs
|
||||
.ent AsmGetRegs
|
||||
.balign 16
|
||||
AsmGetRegs:
|
||||
.cfi_startproc
|
||||
.cfi_def_cfa $sp, 0
|
||||
.set push
|
||||
.set noreorder
|
||||
.cpload $t9
|
||||
sd $zero, 0($a0)
|
||||
.set noat
|
||||
sd $at, 8($a0)
|
||||
.set at
|
||||
sd $v0, 16($a0)
|
||||
sd $v1, 24($a0)
|
||||
sd $a0, 32($a0)
|
||||
sd $a1, 40($a0)
|
||||
sd $a2, 48($a0)
|
||||
sd $a3, 56($a0)
|
||||
sd $a4, 64($a0)
|
||||
sd $a5, 72($a0)
|
||||
sd $a6, 80($a0)
|
||||
sd $a7, 88($a0)
|
||||
sd $t0, 96($a0)
|
||||
sd $t1, 104($a0)
|
||||
sd $t2, 112($a0)
|
||||
sd $t3, 120($a0)
|
||||
sd $s0, 128($a0)
|
||||
sd $s1, 136($a0)
|
||||
sd $s2, 144($a0)
|
||||
sd $s3, 152($a0)
|
||||
sd $s4, 160($a0)
|
||||
sd $s5, 168($a0)
|
||||
sd $s6, 176($a0)
|
||||
sd $s7, 184($a0)
|
||||
sd $t8, 192($a0)
|
||||
sd $t9, 200($a0)
|
||||
sd $k0, 208($a0)
|
||||
sd $k1, 216($a0)
|
||||
sd $gp, 224($a0)
|
||||
sd $sp, 232($a0)
|
||||
sd $s8, 240($a0)
|
||||
sd $ra, 248($a0)
|
||||
jalr $zero, $ra
|
||||
sd $ra, 256($a0) // set PC to the calling function
|
||||
|
||||
.set pop
|
||||
.cfi_endproc
|
||||
.size AsmGetRegs, .-AsmGetRegs
|
||||
.end AsmGetRegs
|
|
@ -189,9 +189,12 @@ ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
|
|||
} else if (e_machine == EM_386) {
|
||||
arch_ = ARCH_X86;
|
||||
interface.reset(new ElfInterface32(memory));
|
||||
} else if (e_machine == EM_MIPS) {
|
||||
arch_ = ARCH_MIPS;
|
||||
interface.reset(new ElfInterface32(memory));
|
||||
} else {
|
||||
// Unsupported.
|
||||
ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
|
||||
ALOGI("32 bit elf that is neither arm nor x86 nor mips: e_machine = %d\n", e_machine);
|
||||
return nullptr;
|
||||
}
|
||||
} else if (class_type_ == ELFCLASS64) {
|
||||
|
@ -205,9 +208,12 @@ ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
|
|||
arch_ = ARCH_ARM64;
|
||||
} else if (e_machine == EM_X86_64) {
|
||||
arch_ = ARCH_X86_64;
|
||||
} else if (e_machine == EM_MIPS) {
|
||||
arch_ = ARCH_MIPS64;
|
||||
} else {
|
||||
// Unsupported.
|
||||
ALOGI("64 bit elf that is neither aarch64 nor x86_64: e_machine = %d\n", e_machine);
|
||||
ALOGI("64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = %d\n",
|
||||
e_machine);
|
||||
return nullptr;
|
||||
}
|
||||
interface.reset(new ElfInterface64(memory));
|
||||
|
|
66
libunwindstack/MachineMips.h
Normal file
66
libunwindstack/MachineMips.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 _LIBUNWINDSTACK_MACHINE_MIPS_H
|
||||
#define _LIBUNWINDSTACK_MACHINE_MIPS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
enum MipsReg : uint16_t {
|
||||
MIPS_REG_R0 = 0,
|
||||
MIPS_REG_R1,
|
||||
MIPS_REG_R2,
|
||||
MIPS_REG_R3,
|
||||
MIPS_REG_R4,
|
||||
MIPS_REG_R5,
|
||||
MIPS_REG_R6,
|
||||
MIPS_REG_R7,
|
||||
MIPS_REG_R8,
|
||||
MIPS_REG_R9,
|
||||
MIPS_REG_R10,
|
||||
MIPS_REG_R11,
|
||||
MIPS_REG_R12,
|
||||
MIPS_REG_R13,
|
||||
MIPS_REG_R14,
|
||||
MIPS_REG_R15,
|
||||
MIPS_REG_R16,
|
||||
MIPS_REG_R17,
|
||||
MIPS_REG_R18,
|
||||
MIPS_REG_R19,
|
||||
MIPS_REG_R20,
|
||||
MIPS_REG_R21,
|
||||
MIPS_REG_R22,
|
||||
MIPS_REG_R23,
|
||||
MIPS_REG_R24,
|
||||
MIPS_REG_R25,
|
||||
MIPS_REG_R26,
|
||||
MIPS_REG_R27,
|
||||
MIPS_REG_R28,
|
||||
MIPS_REG_R29,
|
||||
MIPS_REG_R30,
|
||||
MIPS_REG_R31,
|
||||
MIPS_REG_PC,
|
||||
MIPS_REG_LAST,
|
||||
|
||||
MIPS_REG_SP = MIPS_REG_R29,
|
||||
MIPS_REG_RA = MIPS_REG_R31,
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_MACHINE_MIPS_H
|
66
libunwindstack/MachineMips64.h
Normal file
66
libunwindstack/MachineMips64.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 _LIBUNWINDSTACK_MACHINE_MIPS64_H
|
||||
#define _LIBUNWINDSTACK_MACHINE_MIPS64_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
enum Mips64Reg : uint16_t {
|
||||
MIPS64_REG_R0 = 0,
|
||||
MIPS64_REG_R1,
|
||||
MIPS64_REG_R2,
|
||||
MIPS64_REG_R3,
|
||||
MIPS64_REG_R4,
|
||||
MIPS64_REG_R5,
|
||||
MIPS64_REG_R6,
|
||||
MIPS64_REG_R7,
|
||||
MIPS64_REG_R8,
|
||||
MIPS64_REG_R9,
|
||||
MIPS64_REG_R10,
|
||||
MIPS64_REG_R11,
|
||||
MIPS64_REG_R12,
|
||||
MIPS64_REG_R13,
|
||||
MIPS64_REG_R14,
|
||||
MIPS64_REG_R15,
|
||||
MIPS64_REG_R16,
|
||||
MIPS64_REG_R17,
|
||||
MIPS64_REG_R18,
|
||||
MIPS64_REG_R19,
|
||||
MIPS64_REG_R20,
|
||||
MIPS64_REG_R21,
|
||||
MIPS64_REG_R22,
|
||||
MIPS64_REG_R23,
|
||||
MIPS64_REG_R24,
|
||||
MIPS64_REG_R25,
|
||||
MIPS64_REG_R26,
|
||||
MIPS64_REG_R27,
|
||||
MIPS64_REG_R28,
|
||||
MIPS64_REG_R29,
|
||||
MIPS64_REG_R30,
|
||||
MIPS64_REG_R31,
|
||||
MIPS64_REG_PC,
|
||||
MIPS64_REG_LAST,
|
||||
|
||||
MIPS64_REG_SP = MIPS64_REG_R29,
|
||||
MIPS64_REG_RA = MIPS64_REG_R31,
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_MACHINE_MIPS64_H
|
|
@ -27,16 +27,20 @@
|
|||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/RegsX86.h>
|
||||
#include <unwindstack/RegsX86_64.h>
|
||||
#include <unwindstack/RegsMips.h>
|
||||
#include <unwindstack/RegsMips64.h>
|
||||
|
||||
#include "UserArm.h"
|
||||
#include "UserArm64.h"
|
||||
#include "UserX86.h"
|
||||
#include "UserX86_64.h"
|
||||
#include "UserMips.h"
|
||||
#include "UserMips64.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// The largest user structure.
|
||||
constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
|
||||
constexpr size_t MAX_USER_REGS_SIZE = sizeof(mips64_user_regs) + 10;
|
||||
|
||||
// This function assumes that reg_data is already aligned to a 64 bit value.
|
||||
// If not this could crash with an unaligned access.
|
||||
|
@ -60,6 +64,10 @@ Regs* Regs::RemoteGet(pid_t pid) {
|
|||
return RegsArm::Read(buffer.data());
|
||||
case sizeof(arm64_user_regs):
|
||||
return RegsArm64::Read(buffer.data());
|
||||
case sizeof(mips_user_regs):
|
||||
return RegsMips::Read(buffer.data());
|
||||
case sizeof(mips64_user_regs):
|
||||
return RegsMips64::Read(buffer.data());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -74,6 +82,10 @@ Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) {
|
|||
return RegsArm::CreateFromUcontext(ucontext);
|
||||
case ARCH_ARM64:
|
||||
return RegsArm64::CreateFromUcontext(ucontext);
|
||||
case ARCH_MIPS:
|
||||
return RegsMips::CreateFromUcontext(ucontext);
|
||||
case ARCH_MIPS64:
|
||||
return RegsMips64::CreateFromUcontext(ucontext);
|
||||
case ARCH_UNKNOWN:
|
||||
default:
|
||||
return nullptr;
|
||||
|
@ -89,6 +101,10 @@ ArchEnum Regs::CurrentArch() {
|
|||
return ARCH_X86;
|
||||
#elif defined(__x86_64__)
|
||||
return ARCH_X86_64;
|
||||
#elif defined(__mips__) && !defined(__LP64__)
|
||||
return ARCH_MIPS;
|
||||
#elif defined(__mips__) && defined(__LP64__)
|
||||
return ARCH_MIPS64;
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
|
@ -104,6 +120,10 @@ Regs* Regs::CreateFromLocal() {
|
|||
regs = new RegsX86();
|
||||
#elif defined(__x86_64__)
|
||||
regs = new RegsX86_64();
|
||||
#elif defined(__mips__) && !defined(__LP64__)
|
||||
regs = new RegsMips();
|
||||
#elif defined(__mips__) && defined(__LP64__)
|
||||
regs = new RegsMips64();
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
|
|
173
libunwindstack/RegsMips.cpp
Normal file
173
libunwindstack/RegsMips.cpp
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/RegsMips.h>
|
||||
|
||||
#include "MachineMips.h"
|
||||
#include "UcontextMips.h"
|
||||
#include "UserMips.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
RegsMips::RegsMips()
|
||||
: RegsImpl<uint32_t>(MIPS_REG_LAST, MIPS_REG_SP, Location(LOCATION_REGISTER, MIPS_REG_RA)) {}
|
||||
|
||||
ArchEnum RegsMips::Arch() {
|
||||
return ARCH_MIPS;
|
||||
}
|
||||
|
||||
uint64_t RegsMips::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
|
||||
if (!elf->valid()) {
|
||||
return rel_pc;
|
||||
}
|
||||
|
||||
// For now, just assuming no compact branches
|
||||
if (rel_pc < 8) {
|
||||
return rel_pc;
|
||||
}
|
||||
return rel_pc - 8;
|
||||
}
|
||||
|
||||
void RegsMips::SetFromRaw() {
|
||||
set_pc(regs_[MIPS_REG_PC]);
|
||||
set_sp(regs_[MIPS_REG_SP]);
|
||||
}
|
||||
|
||||
bool RegsMips::SetPcFromReturnAddress(Memory*) {
|
||||
if (pc() == regs_[MIPS_REG_RA]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set_pc(regs_[MIPS_REG_RA]);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RegsMips::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
|
||||
fn("r0", regs_[MIPS_REG_R0]);
|
||||
fn("r1", regs_[MIPS_REG_R1]);
|
||||
fn("r2", regs_[MIPS_REG_R2]);
|
||||
fn("r3", regs_[MIPS_REG_R3]);
|
||||
fn("r4", regs_[MIPS_REG_R4]);
|
||||
fn("r5", regs_[MIPS_REG_R5]);
|
||||
fn("r6", regs_[MIPS_REG_R6]);
|
||||
fn("r7", regs_[MIPS_REG_R7]);
|
||||
fn("r8", regs_[MIPS_REG_R8]);
|
||||
fn("r9", regs_[MIPS_REG_R9]);
|
||||
fn("r10", regs_[MIPS_REG_R10]);
|
||||
fn("r11", regs_[MIPS_REG_R11]);
|
||||
fn("r12", regs_[MIPS_REG_R12]);
|
||||
fn("r13", regs_[MIPS_REG_R13]);
|
||||
fn("r14", regs_[MIPS_REG_R14]);
|
||||
fn("r15", regs_[MIPS_REG_R15]);
|
||||
fn("r16", regs_[MIPS_REG_R16]);
|
||||
fn("r17", regs_[MIPS_REG_R17]);
|
||||
fn("r18", regs_[MIPS_REG_R18]);
|
||||
fn("r19", regs_[MIPS_REG_R19]);
|
||||
fn("r20", regs_[MIPS_REG_R20]);
|
||||
fn("r21", regs_[MIPS_REG_R21]);
|
||||
fn("r22", regs_[MIPS_REG_R22]);
|
||||
fn("r23", regs_[MIPS_REG_R23]);
|
||||
fn("r24", regs_[MIPS_REG_R24]);
|
||||
fn("r25", regs_[MIPS_REG_R25]);
|
||||
fn("r26", regs_[MIPS_REG_R26]);
|
||||
fn("r27", regs_[MIPS_REG_R27]);
|
||||
fn("r28", regs_[MIPS_REG_R28]);
|
||||
fn("sp", regs_[MIPS_REG_SP]);
|
||||
fn("r30", regs_[MIPS_REG_R30]);
|
||||
fn("ra", regs_[MIPS_REG_RA]);
|
||||
fn("pc", regs_[MIPS_REG_PC]);
|
||||
}
|
||||
|
||||
Regs* RegsMips::Read(void* remote_data) {
|
||||
mips_user_regs* user = reinterpret_cast<mips_user_regs*>(remote_data);
|
||||
RegsMips* regs = new RegsMips();
|
||||
uint32_t* reg_data = reinterpret_cast<uint32_t*>(regs->RawData());
|
||||
|
||||
memcpy(regs->RawData(), &user->regs[MIPS32_EF_R0], (MIPS_REG_R31 + 1) * sizeof(uint32_t));
|
||||
|
||||
reg_data[MIPS_REG_PC] = user->regs[MIPS32_EF_CP0_EPC];
|
||||
regs->SetFromRaw();
|
||||
return regs;
|
||||
}
|
||||
|
||||
Regs* RegsMips::CreateFromUcontext(void* ucontext) {
|
||||
mips_ucontext_t* mips_ucontext = reinterpret_cast<mips_ucontext_t*>(ucontext);
|
||||
|
||||
RegsMips* regs = new RegsMips();
|
||||
// Copy 64 bit sc_regs over to 32 bit regs
|
||||
for (int i = 0; i < 32; i++) {
|
||||
(*regs)[MIPS_REG_R0 + i] = mips_ucontext->uc_mcontext.sc_regs[i];
|
||||
}
|
||||
(*regs)[MIPS_REG_PC] = mips_ucontext->uc_mcontext.sc_pc;
|
||||
regs->SetFromRaw();
|
||||
return regs;
|
||||
}
|
||||
|
||||
bool RegsMips::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
|
||||
uint64_t data;
|
||||
uint64_t offset = 0;
|
||||
Memory* elf_memory = elf->memory();
|
||||
// Read from elf memory since it is usually more expensive to read from
|
||||
// process memory.
|
||||
if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look for the kernel sigreturn functions.
|
||||
// __vdso_rt_sigreturn:
|
||||
// 0x24021061 li v0, 0x1061
|
||||
// 0x0000000c syscall
|
||||
// __vdso_sigreturn:
|
||||
// 0x24021017 li v0, 0x1017
|
||||
// 0x0000000c syscall
|
||||
if (data == 0x0000000c24021061ULL) {
|
||||
// vdso_rt_sigreturn => read rt_sigframe
|
||||
// offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset + sc_pc offset
|
||||
offset = 24 + 128 + 24 + 8;
|
||||
} else if (data == 0x0000000c24021017LL) {
|
||||
// vdso_sigreturn => read sigframe
|
||||
// offset = sigcontext offset + sc_pc offset
|
||||
offset = 24 + 8;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// read sc_pc and sc_regs[32] from stack
|
||||
uint64_t values[MIPS_REG_LAST];
|
||||
if (!process_memory->Read(sp() + offset, values, sizeof(values))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy 64 bit sc_pc over to 32 bit regs_[MIPS_REG_PC]
|
||||
regs_[MIPS_REG_PC] = values[0];
|
||||
|
||||
// Copy 64 bit sc_regs over to 32 bit regs
|
||||
for (int i = 0; i < 32; i++) {
|
||||
regs_[MIPS_REG_R0 + i] = values[1 + i];
|
||||
}
|
||||
|
||||
SetFromRaw();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
161
libunwindstack/RegsMips64.cpp
Normal file
161
libunwindstack/RegsMips64.cpp
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/RegsMips64.h>
|
||||
|
||||
#include "MachineMips64.h"
|
||||
#include "UcontextMips64.h"
|
||||
#include "UserMips64.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
RegsMips64::RegsMips64()
|
||||
: RegsImpl<uint64_t>(MIPS64_REG_LAST, MIPS64_REG_SP,
|
||||
Location(LOCATION_REGISTER, MIPS64_REG_RA)) {}
|
||||
|
||||
ArchEnum RegsMips64::Arch() {
|
||||
return ARCH_MIPS64;
|
||||
}
|
||||
|
||||
uint64_t RegsMips64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
|
||||
if (!elf->valid()) {
|
||||
return rel_pc;
|
||||
}
|
||||
|
||||
// For now, just assuming no compact branches
|
||||
if (rel_pc < 8) {
|
||||
return rel_pc;
|
||||
}
|
||||
return rel_pc - 8;
|
||||
}
|
||||
|
||||
void RegsMips64::SetFromRaw() {
|
||||
set_pc(regs_[MIPS64_REG_PC]);
|
||||
set_sp(regs_[MIPS64_REG_SP]);
|
||||
}
|
||||
|
||||
bool RegsMips64::SetPcFromReturnAddress(Memory*) {
|
||||
if (pc() == regs_[MIPS64_REG_RA]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set_pc(regs_[MIPS64_REG_RA]);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RegsMips64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
|
||||
fn("r0", regs_[MIPS64_REG_R0]);
|
||||
fn("r1", regs_[MIPS64_REG_R1]);
|
||||
fn("r2", regs_[MIPS64_REG_R2]);
|
||||
fn("r3", regs_[MIPS64_REG_R3]);
|
||||
fn("r4", regs_[MIPS64_REG_R4]);
|
||||
fn("r5", regs_[MIPS64_REG_R5]);
|
||||
fn("r6", regs_[MIPS64_REG_R6]);
|
||||
fn("r7", regs_[MIPS64_REG_R7]);
|
||||
fn("r8", regs_[MIPS64_REG_R8]);
|
||||
fn("r9", regs_[MIPS64_REG_R9]);
|
||||
fn("r10", regs_[MIPS64_REG_R10]);
|
||||
fn("r11", regs_[MIPS64_REG_R11]);
|
||||
fn("r12", regs_[MIPS64_REG_R12]);
|
||||
fn("r13", regs_[MIPS64_REG_R13]);
|
||||
fn("r14", regs_[MIPS64_REG_R14]);
|
||||
fn("r15", regs_[MIPS64_REG_R15]);
|
||||
fn("r16", regs_[MIPS64_REG_R16]);
|
||||
fn("r17", regs_[MIPS64_REG_R17]);
|
||||
fn("r18", regs_[MIPS64_REG_R18]);
|
||||
fn("r19", regs_[MIPS64_REG_R19]);
|
||||
fn("r20", regs_[MIPS64_REG_R20]);
|
||||
fn("r21", regs_[MIPS64_REG_R21]);
|
||||
fn("r22", regs_[MIPS64_REG_R22]);
|
||||
fn("r23", regs_[MIPS64_REG_R23]);
|
||||
fn("r24", regs_[MIPS64_REG_R24]);
|
||||
fn("r25", regs_[MIPS64_REG_R25]);
|
||||
fn("r26", regs_[MIPS64_REG_R26]);
|
||||
fn("r27", regs_[MIPS64_REG_R27]);
|
||||
fn("r28", regs_[MIPS64_REG_R28]);
|
||||
fn("sp", regs_[MIPS64_REG_SP]);
|
||||
fn("r30", regs_[MIPS64_REG_R30]);
|
||||
fn("ra", regs_[MIPS64_REG_RA]);
|
||||
fn("pc", regs_[MIPS64_REG_PC]);
|
||||
}
|
||||
|
||||
Regs* RegsMips64::Read(void* remote_data) {
|
||||
mips64_user_regs* user = reinterpret_cast<mips64_user_regs*>(remote_data);
|
||||
RegsMips64* regs = new RegsMips64();
|
||||
uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
|
||||
|
||||
memcpy(regs->RawData(), &user->regs[MIPS64_EF_R0], (MIPS64_REG_R31 + 1) * sizeof(uint64_t));
|
||||
|
||||
reg_data[MIPS64_REG_PC] = user->regs[MIPS64_EF_CP0_EPC];
|
||||
regs->SetFromRaw();
|
||||
return regs;
|
||||
}
|
||||
|
||||
Regs* RegsMips64::CreateFromUcontext(void* ucontext) {
|
||||
mips64_ucontext_t* mips64_ucontext = reinterpret_cast<mips64_ucontext_t*>(ucontext);
|
||||
|
||||
RegsMips64* regs = new RegsMips64();
|
||||
// Copy 64 bit sc_regs over to 64 bit regs
|
||||
memcpy(regs->RawData(), &mips64_ucontext->uc_mcontext.sc_regs[0], 32 * sizeof(uint64_t));
|
||||
(*regs)[MIPS64_REG_PC] = mips64_ucontext->uc_mcontext.sc_pc;
|
||||
regs->SetFromRaw();
|
||||
return regs;
|
||||
}
|
||||
|
||||
bool RegsMips64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
|
||||
uint64_t data;
|
||||
Memory* elf_memory = elf->memory();
|
||||
// Read from elf memory since it is usually more expensive to read from
|
||||
// process memory.
|
||||
if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look for the kernel sigreturn function.
|
||||
// __vdso_rt_sigreturn:
|
||||
// 0x2402145b li v0, 0x145b
|
||||
// 0x0000000c syscall
|
||||
if (data != 0x0000000c2402145bULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// vdso_rt_sigreturn => read rt_sigframe
|
||||
// offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset
|
||||
// read 64 bit sc_regs[32] from stack into 64 bit regs_
|
||||
if (!process_memory->Read(sp() + 24 + 128 + 40, regs_.data(),
|
||||
sizeof(uint64_t) * (MIPS64_REG_LAST - 1))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset + sc_pc offset
|
||||
// read 64 bit sc_pc from stack into 64 bit regs_[MIPS64_REG_PC]
|
||||
if (!process_memory->Read(sp() + 24 + 128 + 40 + 576, ®s_[MIPS64_REG_PC],
|
||||
sizeof(uint64_t))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetFromRaw();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
62
libunwindstack/UcontextMips.h
Normal file
62
libunwindstack/UcontextMips.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBUNWINDSTACK_UCONTEXT_MIPS_H
|
||||
#define _LIBUNWINDSTACK_UCONTEXT_MIPS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "MachineMips.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
struct mips_stack_t {
|
||||
uint32_t ss_sp; // void __user*
|
||||
uint32_t ss_size; // size_t
|
||||
int32_t ss_flags; // int
|
||||
};
|
||||
|
||||
struct mips_mcontext_t {
|
||||
uint32_t sc_regmask;
|
||||
uint32_t sc_status;
|
||||
uint64_t sc_pc;
|
||||
uint64_t sc_regs[32];
|
||||
// Nothing else is used, so don't define it.
|
||||
};
|
||||
|
||||
struct mips_ucontext_t {
|
||||
uint32_t uc_flags; // unsigned long
|
||||
uint32_t uc_link; // struct ucontext*
|
||||
mips_stack_t uc_stack;
|
||||
mips_mcontext_t uc_mcontext;
|
||||
// Nothing else is used, so don't define it.
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_UCONTEXT_MIPS_H
|
69
libunwindstack/UcontextMips64.h
Normal file
69
libunwindstack/UcontextMips64.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
|
||||
#define _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "MachineMips64.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
struct mips64_stack_t {
|
||||
uint64_t ss_sp; // void __user*
|
||||
uint64_t ss_size; // size_t
|
||||
int32_t ss_flags; // int
|
||||
};
|
||||
|
||||
struct mips64_mcontext_t {
|
||||
uint64_t sc_regs[32];
|
||||
uint64_t sc_fpregs[32];
|
||||
uint64_t sc_mdhi;
|
||||
uint64_t sc_hi1;
|
||||
uint64_t sc_hi2;
|
||||
uint64_t sc_hi3;
|
||||
uint64_t sc_mdlo;
|
||||
uint64_t sc_lo1;
|
||||
uint64_t sc_lo2;
|
||||
uint64_t sc_lo3;
|
||||
uint64_t sc_pc;
|
||||
// Nothing else is used, so don't define it.
|
||||
};
|
||||
|
||||
struct mips64_ucontext_t {
|
||||
uint64_t uc_flags; // unsigned long
|
||||
uint64_t uc_link; // struct ucontext*
|
||||
mips64_stack_t uc_stack;
|
||||
mips64_mcontext_t uc_mcontext;
|
||||
// Nothing else is used, so don't define it.
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_UCONTEXT_MIPS6464_H
|
45
libunwindstack/UserMips.h
Normal file
45
libunwindstack/UserMips.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBUNWINDSTACK_USER_MIPS_H
|
||||
#define _LIBUNWINDSTACK_USER_MIPS_H
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
enum Mips32UserReg : uint16_t {
|
||||
MIPS32_EF_R0 = 6,
|
||||
MIPS32_EF_CP0_EPC = 40,
|
||||
};
|
||||
|
||||
struct mips_user_regs {
|
||||
uint32_t regs[45];
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_USER_MIPS_H
|
45
libunwindstack/UserMips64.h
Normal file
45
libunwindstack/UserMips64.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBUNWINDSTACK_USER_MIPS64_H
|
||||
#define _LIBUNWINDSTACK_USER_MIPS64_H
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
enum Mips64UserReg : uint16_t {
|
||||
MIPS64_EF_R0 = 0,
|
||||
MIPS64_EF_CP0_EPC = 34,
|
||||
};
|
||||
|
||||
struct mips64_user_regs {
|
||||
uint64_t regs[45];
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_USER_MIPS64_H
|
|
@ -42,6 +42,8 @@ enum ArchEnum : uint8_t {
|
|||
ARCH_ARM64,
|
||||
ARCH_X86,
|
||||
ARCH_X86_64,
|
||||
ARCH_MIPS,
|
||||
ARCH_MIPS64,
|
||||
};
|
||||
|
||||
class Elf {
|
||||
|
|
|
@ -87,7 +87,7 @@ inline __always_inline void RegsGetLocal(Regs* regs) {
|
|||
regs->SetFromRaw();
|
||||
}
|
||||
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
#elif defined(__i386__) || defined(__x86_64__) || defined(__mips__)
|
||||
|
||||
extern "C" void AsmGetRegs(void* regs);
|
||||
|
||||
|
@ -97,11 +97,6 @@ inline void RegsGetLocal(Regs* regs) {
|
|||
regs->SetFromRaw();
|
||||
}
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
// Stub to allow mips to build.
|
||||
void RegsGetLocal(Regs*) {}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
56
libunwindstack/include/unwindstack/RegsMips.h
Normal file
56
libunwindstack/include/unwindstack/RegsMips.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 _LIBUNWINDSTACK_REGS_MIPS_H
|
||||
#define _LIBUNWINDSTACK_REGS_MIPS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Memory;
|
||||
|
||||
class RegsMips : public RegsImpl<uint32_t> {
|
||||
public:
|
||||
RegsMips();
|
||||
virtual ~RegsMips() = default;
|
||||
|
||||
virtual ArchEnum Arch() override final;
|
||||
|
||||
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
|
||||
|
||||
void SetFromRaw() override;
|
||||
|
||||
bool SetPcFromReturnAddress(Memory* process_memory) override;
|
||||
|
||||
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
|
||||
|
||||
virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
|
||||
|
||||
static Regs* Read(void* data);
|
||||
|
||||
static Regs* CreateFromUcontext(void* ucontext);
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_REGS_MIPS_H
|
56
libunwindstack/include/unwindstack/RegsMips64.h
Normal file
56
libunwindstack/include/unwindstack/RegsMips64.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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 _LIBUNWINDSTACK_REGS_MIPS64_H
|
||||
#define _LIBUNWINDSTACK_REGS_MIPS64_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Memory;
|
||||
|
||||
class RegsMips64 : public RegsImpl<uint64_t> {
|
||||
public:
|
||||
RegsMips64();
|
||||
virtual ~RegsMips64() = default;
|
||||
|
||||
virtual ArchEnum Arch() override final;
|
||||
|
||||
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
|
||||
|
||||
void SetFromRaw() override;
|
||||
|
||||
bool SetPcFromReturnAddress(Memory* process_memory) override;
|
||||
|
||||
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
|
||||
|
||||
virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
|
||||
|
||||
static Regs* Read(void* data);
|
||||
|
||||
static Regs* CreateFromUcontext(void* ucontext);
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_REGS_MIPS64_H
|
|
@ -145,7 +145,7 @@ TEST_F(ElfTest, elf32_invalid_machine) {
|
|||
ASSERT_FALSE(elf.Init(false));
|
||||
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
|
||||
ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86 nor mips: e_machine = 20\n\n",
|
||||
GetFakeLogPrint());
|
||||
}
|
||||
|
||||
|
@ -158,7 +158,7 @@ TEST_F(ElfTest, elf64_invalid_machine) {
|
|||
ASSERT_FALSE(elf.Init(false));
|
||||
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
|
||||
ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = 21\n\n",
|
||||
GetFakeLogPrint());
|
||||
}
|
||||
|
||||
|
@ -174,6 +174,18 @@ TEST_F(ElfTest, elf_arm) {
|
|||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, elf_mips) {
|
||||
Elf elf(memory_);
|
||||
|
||||
InitElf32(EM_MIPS);
|
||||
|
||||
ASSERT_TRUE(elf.Init(false));
|
||||
ASSERT_TRUE(elf.valid());
|
||||
ASSERT_EQ(static_cast<uint32_t>(EM_MIPS), elf.machine_type());
|
||||
ASSERT_EQ(ELFCLASS32, elf.class_type());
|
||||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, elf_x86) {
|
||||
Elf elf(memory_);
|
||||
|
||||
|
@ -210,6 +222,18 @@ TEST_F(ElfTest, elf_x86_64) {
|
|||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, elf_mips64) {
|
||||
Elf elf(memory_);
|
||||
|
||||
InitElf64(EM_MIPS);
|
||||
|
||||
ASSERT_TRUE(elf.Init(false));
|
||||
ASSERT_TRUE(elf.valid());
|
||||
ASSERT_EQ(static_cast<uint32_t>(EM_MIPS), elf.machine_type());
|
||||
ASSERT_EQ(ELFCLASS64, elf.class_type());
|
||||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, gnu_debugdata_init_fail32) {
|
||||
TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
|
||||
[&](uint64_t offset, const void* ptr, size_t size) {
|
||||
|
|
|
@ -29,11 +29,15 @@
|
|||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/RegsX86.h>
|
||||
#include <unwindstack/RegsX86_64.h>
|
||||
#include <unwindstack/RegsMips.h>
|
||||
#include <unwindstack/RegsMips64.h>
|
||||
|
||||
#include "MachineArm.h"
|
||||
#include "MachineArm64.h"
|
||||
#include "MachineX86.h"
|
||||
#include "MachineX86_64.h"
|
||||
#include "MachineMips.h"
|
||||
#include "MachineMips64.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
|
@ -152,7 +156,87 @@ std::vector<Register> ExpectedRegisters<RegsX86_64>() {
|
|||
return result;
|
||||
}
|
||||
|
||||
using RegTypes = ::testing::Types<RegsArm, RegsArm64, RegsX86, RegsX86_64>;
|
||||
template<>
|
||||
std::vector<Register> ExpectedRegisters<RegsMips>() {
|
||||
std::vector<Register> result;
|
||||
result.push_back({"r0", MIPS_REG_R0});
|
||||
result.push_back({"r1", MIPS_REG_R1});
|
||||
result.push_back({"r2", MIPS_REG_R2});
|
||||
result.push_back({"r3", MIPS_REG_R3});
|
||||
result.push_back({"r4", MIPS_REG_R4});
|
||||
result.push_back({"r5", MIPS_REG_R5});
|
||||
result.push_back({"r6", MIPS_REG_R6});
|
||||
result.push_back({"r7", MIPS_REG_R7});
|
||||
result.push_back({"r8", MIPS_REG_R8});
|
||||
result.push_back({"r9", MIPS_REG_R9});
|
||||
result.push_back({"r10", MIPS_REG_R10});
|
||||
result.push_back({"r11", MIPS_REG_R11});
|
||||
result.push_back({"r12", MIPS_REG_R12});
|
||||
result.push_back({"r13", MIPS_REG_R13});
|
||||
result.push_back({"r14", MIPS_REG_R14});
|
||||
result.push_back({"r15", MIPS_REG_R15});
|
||||
result.push_back({"r16", MIPS_REG_R16});
|
||||
result.push_back({"r17", MIPS_REG_R17});
|
||||
result.push_back({"r18", MIPS_REG_R18});
|
||||
result.push_back({"r19", MIPS_REG_R19});
|
||||
result.push_back({"r20", MIPS_REG_R20});
|
||||
result.push_back({"r21", MIPS_REG_R21});
|
||||
result.push_back({"r22", MIPS_REG_R22});
|
||||
result.push_back({"r23", MIPS_REG_R23});
|
||||
result.push_back({"r24", MIPS_REG_R24});
|
||||
result.push_back({"r25", MIPS_REG_R25});
|
||||
result.push_back({"r26", MIPS_REG_R26});
|
||||
result.push_back({"r27", MIPS_REG_R27});
|
||||
result.push_back({"r28", MIPS_REG_R28});
|
||||
result.push_back({"sp", MIPS_REG_SP});
|
||||
result.push_back({"r30", MIPS_REG_R30});
|
||||
result.push_back({"ra", MIPS_REG_RA});
|
||||
result.push_back({"pc", MIPS_REG_PC});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::vector<Register> ExpectedRegisters<RegsMips64>() {
|
||||
std::vector<Register> result;
|
||||
result.push_back({"r0", MIPS64_REG_R0});
|
||||
result.push_back({"r1", MIPS64_REG_R1});
|
||||
result.push_back({"r2", MIPS64_REG_R2});
|
||||
result.push_back({"r3", MIPS64_REG_R3});
|
||||
result.push_back({"r4", MIPS64_REG_R4});
|
||||
result.push_back({"r5", MIPS64_REG_R5});
|
||||
result.push_back({"r6", MIPS64_REG_R6});
|
||||
result.push_back({"r7", MIPS64_REG_R7});
|
||||
result.push_back({"r8", MIPS64_REG_R8});
|
||||
result.push_back({"r9", MIPS64_REG_R9});
|
||||
result.push_back({"r10", MIPS64_REG_R10});
|
||||
result.push_back({"r11", MIPS64_REG_R11});
|
||||
result.push_back({"r12", MIPS64_REG_R12});
|
||||
result.push_back({"r13", MIPS64_REG_R13});
|
||||
result.push_back({"r14", MIPS64_REG_R14});
|
||||
result.push_back({"r15", MIPS64_REG_R15});
|
||||
result.push_back({"r16", MIPS64_REG_R16});
|
||||
result.push_back({"r17", MIPS64_REG_R17});
|
||||
result.push_back({"r18", MIPS64_REG_R18});
|
||||
result.push_back({"r19", MIPS64_REG_R19});
|
||||
result.push_back({"r20", MIPS64_REG_R20});
|
||||
result.push_back({"r21", MIPS64_REG_R21});
|
||||
result.push_back({"r22", MIPS64_REG_R22});
|
||||
result.push_back({"r23", MIPS64_REG_R23});
|
||||
result.push_back({"r24", MIPS64_REG_R24});
|
||||
result.push_back({"r25", MIPS64_REG_R25});
|
||||
result.push_back({"r26", MIPS64_REG_R26});
|
||||
result.push_back({"r27", MIPS64_REG_R27});
|
||||
result.push_back({"r28", MIPS64_REG_R28});
|
||||
result.push_back({"sp", MIPS64_REG_SP});
|
||||
result.push_back({"r30", MIPS64_REG_R30});
|
||||
result.push_back({"ra", MIPS64_REG_RA});
|
||||
result.push_back({"pc", MIPS64_REG_PC});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
using RegTypes = ::testing::Types<RegsArm, RegsArm64, RegsX86, RegsX86_64, RegsMips, RegsMips64>;
|
||||
TYPED_TEST_CASE(RegsIterateTest, RegTypes);
|
||||
|
||||
TYPED_TEST(RegsIterateTest, iterate) {
|
||||
|
|
|
@ -23,11 +23,15 @@
|
|||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/RegsX86.h>
|
||||
#include <unwindstack/RegsX86_64.h>
|
||||
#include <unwindstack/RegsMips.h>
|
||||
#include <unwindstack/RegsMips64.h>
|
||||
|
||||
#include "MachineArm.h"
|
||||
#include "MachineArm64.h"
|
||||
#include "MachineX86.h"
|
||||
#include "MachineX86_64.h"
|
||||
#include "MachineMips.h"
|
||||
#include "MachineMips64.h"
|
||||
|
||||
#include "MemoryFake.h"
|
||||
|
||||
|
@ -204,4 +208,64 @@ TEST_F(RegsStepIfSignalHandlerTest, x86_64_step_if_signal_handler) {
|
|||
EXPECT_EQ(0x150U, regs.pc());
|
||||
}
|
||||
|
||||
TEST_F(RegsStepIfSignalHandlerTest, mips_step_if_signal_handler_non_rt) {
|
||||
uint64_t addr = 0x1000;
|
||||
RegsMips regs;
|
||||
regs[MIPS_REG_PC] = 0x8000;
|
||||
regs[MIPS_REG_SP] = addr;
|
||||
regs.SetFromRaw();
|
||||
|
||||
elf_memory_->SetData64(0x8000, 0x0000000c24021017ULL);
|
||||
|
||||
for (uint64_t index = 0; index <= 50; index++) {
|
||||
process_memory_.SetData64(addr + index * 8, index * 0x10);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
|
||||
EXPECT_EQ(0x220U, regs[MIPS_REG_SP]);
|
||||
EXPECT_EQ(0x040U, regs[MIPS_REG_PC]);
|
||||
EXPECT_EQ(0x220U, regs.sp());
|
||||
EXPECT_EQ(0x040U, regs.pc());
|
||||
}
|
||||
|
||||
TEST_F(RegsStepIfSignalHandlerTest, mips_step_if_signal_handler_rt) {
|
||||
uint64_t addr = 0x1000;
|
||||
RegsMips regs;
|
||||
regs[MIPS_REG_PC] = 0x8000;
|
||||
regs[MIPS_REG_SP] = addr;
|
||||
regs.SetFromRaw();
|
||||
|
||||
elf_memory_->SetData64(0x8000, 0x0000000c24021061ULL);
|
||||
|
||||
for (uint64_t index = 0; index <= 100; index++) {
|
||||
process_memory_.SetData64(addr + index * 8, index * 0x10);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
|
||||
EXPECT_EQ(0x350U, regs[MIPS_REG_SP]);
|
||||
EXPECT_EQ(0x170U, regs[MIPS_REG_PC]);
|
||||
EXPECT_EQ(0x350U, regs.sp());
|
||||
EXPECT_EQ(0x170U, regs.pc());
|
||||
}
|
||||
|
||||
TEST_F(RegsStepIfSignalHandlerTest, mips64_step_if_signal_handler) {
|
||||
uint64_t addr = 0x1000;
|
||||
RegsMips64 regs;
|
||||
regs[MIPS64_REG_PC] = 0x8000;
|
||||
regs[MIPS64_REG_SP] = addr;
|
||||
regs.SetFromRaw();
|
||||
|
||||
elf_memory_->SetData64(0x8000, 0x0000000c2402145bULL);
|
||||
|
||||
for (uint64_t index = 0; index <= 100; index++) {
|
||||
process_memory_.SetData64(addr + index * 8, index * 0x10);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
|
||||
EXPECT_EQ(0x350U, regs[MIPS64_REG_SP]);
|
||||
EXPECT_EQ(0x600U, regs[MIPS64_REG_PC]);
|
||||
EXPECT_EQ(0x350U, regs.sp());
|
||||
EXPECT_EQ(0x600U, regs.pc());
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/RegsX86.h>
|
||||
#include <unwindstack/RegsX86_64.h>
|
||||
#include <unwindstack/RegsMips.h>
|
||||
#include <unwindstack/RegsMips64.h>
|
||||
|
||||
#include "ElfFake.h"
|
||||
#include "MemoryFake.h"
|
||||
|
@ -112,6 +114,30 @@ TEST_F(RegsTest, rel_pc) {
|
|||
ASSERT_EQ(0x1U, x86_64.GetAdjustedPc(0x2, elf_.get()));
|
||||
ASSERT_EQ(0x0U, x86_64.GetAdjustedPc(0x1, elf_.get()));
|
||||
ASSERT_EQ(0x0U, x86_64.GetAdjustedPc(0x0, elf_.get()));
|
||||
|
||||
RegsMips mips;
|
||||
ASSERT_EQ(0x8U, mips.GetAdjustedPc(0x10, elf_.get()));
|
||||
ASSERT_EQ(0x0U, mips.GetAdjustedPc(0x8, elf_.get()));
|
||||
ASSERT_EQ(0x7U, mips.GetAdjustedPc(0x7, elf_.get()));
|
||||
ASSERT_EQ(0x6U, mips.GetAdjustedPc(0x6, elf_.get()));
|
||||
ASSERT_EQ(0x5U, mips.GetAdjustedPc(0x5, elf_.get()));
|
||||
ASSERT_EQ(0x4U, mips.GetAdjustedPc(0x4, elf_.get()));
|
||||
ASSERT_EQ(0x3U, mips.GetAdjustedPc(0x3, elf_.get()));
|
||||
ASSERT_EQ(0x2U, mips.GetAdjustedPc(0x2, elf_.get()));
|
||||
ASSERT_EQ(0x1U, mips.GetAdjustedPc(0x1, elf_.get()));
|
||||
ASSERT_EQ(0x0U, mips.GetAdjustedPc(0x0, elf_.get()));
|
||||
|
||||
RegsMips64 mips64;
|
||||
ASSERT_EQ(0x8U, mips64.GetAdjustedPc(0x10, elf_.get()));
|
||||
ASSERT_EQ(0x0U, mips64.GetAdjustedPc(0x8, elf_.get()));
|
||||
ASSERT_EQ(0x7U, mips64.GetAdjustedPc(0x7, elf_.get()));
|
||||
ASSERT_EQ(0x6U, mips64.GetAdjustedPc(0x6, elf_.get()));
|
||||
ASSERT_EQ(0x5U, mips64.GetAdjustedPc(0x5, elf_.get()));
|
||||
ASSERT_EQ(0x4U, mips64.GetAdjustedPc(0x4, elf_.get()));
|
||||
ASSERT_EQ(0x3U, mips64.GetAdjustedPc(0x3, elf_.get()));
|
||||
ASSERT_EQ(0x2U, mips64.GetAdjustedPc(0x2, elf_.get()));
|
||||
ASSERT_EQ(0x1U, mips64.GetAdjustedPc(0x1, elf_.get()));
|
||||
ASSERT_EQ(0x0U, mips64.GetAdjustedPc(0x0, elf_.get()));
|
||||
}
|
||||
|
||||
TEST_F(RegsTest, rel_pc_arm) {
|
||||
|
@ -154,6 +180,8 @@ TEST_F(RegsTest, elf_invalid) {
|
|||
RegsArm64 regs_arm64;
|
||||
RegsX86 regs_x86;
|
||||
RegsX86_64 regs_x86_64;
|
||||
RegsMips regs_mips;
|
||||
RegsMips64 regs_mips64;
|
||||
MapInfo map_info(0x1000, 0x2000);
|
||||
Elf* invalid_elf = new Elf(new MemoryFake);
|
||||
map_info.elf = invalid_elf;
|
||||
|
@ -173,6 +201,14 @@ TEST_F(RegsTest, elf_invalid) {
|
|||
regs_x86_64.set_pc(0x1800);
|
||||
EXPECT_EQ(0x800U, invalid_elf->GetRelPc(regs_x86_64.pc(), &map_info));
|
||||
EXPECT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, invalid_elf));
|
||||
|
||||
regs_mips.set_pc(0x1900);
|
||||
EXPECT_EQ(0x900U, invalid_elf->GetRelPc(regs_mips.pc(), &map_info));
|
||||
EXPECT_EQ(0x900U, regs_mips.GetAdjustedPc(0x900U, invalid_elf));
|
||||
|
||||
regs_mips64.set_pc(0x1a00);
|
||||
EXPECT_EQ(0xa00U, invalid_elf->GetRelPc(regs_mips64.pc(), &map_info));
|
||||
EXPECT_EQ(0xa00U, regs_mips64.GetAdjustedPc(0xa00U, invalid_elf));
|
||||
}
|
||||
|
||||
TEST_F(RegsTest, arm_set_from_raw) {
|
||||
|
@ -215,6 +251,26 @@ TEST_F(RegsTest, x86_64_set_from_raw) {
|
|||
EXPECT_EQ(0x4900000000U, x86_64.pc());
|
||||
}
|
||||
|
||||
TEST_F(RegsTest, mips_set_from_raw) {
|
||||
RegsMips mips;
|
||||
uint32_t* regs = reinterpret_cast<uint32_t*>(mips.RawData());
|
||||
regs[29] = 0x100;
|
||||
regs[32] = 0x200;
|
||||
mips.SetFromRaw();
|
||||
EXPECT_EQ(0x100U, mips.sp());
|
||||
EXPECT_EQ(0x200U, mips.pc());
|
||||
}
|
||||
|
||||
TEST_F(RegsTest, mips64_set_from_raw) {
|
||||
RegsMips64 mips64;
|
||||
uint64_t* regs = reinterpret_cast<uint64_t*>(mips64.RawData());
|
||||
regs[29] = 0xb100000000ULL;
|
||||
regs[32] = 0xc200000000ULL;
|
||||
mips64.SetFromRaw();
|
||||
EXPECT_EQ(0xb100000000U, mips64.sp());
|
||||
EXPECT_EQ(0xc200000000U, mips64.pc());
|
||||
}
|
||||
|
||||
TEST_F(RegsTest, machine_type) {
|
||||
RegsArm arm_regs;
|
||||
EXPECT_EQ(ARCH_ARM, arm_regs.Arch());
|
||||
|
@ -227,6 +283,12 @@ TEST_F(RegsTest, machine_type) {
|
|||
|
||||
RegsX86_64 x86_64_regs;
|
||||
EXPECT_EQ(ARCH_X86_64, x86_64_regs.Arch());
|
||||
|
||||
RegsMips mips_regs;
|
||||
EXPECT_EQ(ARCH_MIPS, mips_regs.Arch());
|
||||
|
||||
RegsMips64 mips64_regs;
|
||||
EXPECT_EQ(ARCH_MIPS64, mips64_regs.Arch());
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/RegsX86.h>
|
||||
#include <unwindstack/RegsX86_64.h>
|
||||
#include <unwindstack/RegsMips.h>
|
||||
#include <unwindstack/RegsMips64.h>
|
||||
#include <unwindstack/Unwinder.h>
|
||||
|
||||
#include "ElfFake.h"
|
||||
|
@ -733,6 +735,16 @@ TEST_F(UnwinderTest, format_frame) {
|
|||
x86_64->set_sp(0x10000);
|
||||
reg_list.push_back(x86_64);
|
||||
|
||||
RegsMips* mips = new RegsMips;
|
||||
mips->set_pc(0x2300);
|
||||
mips->set_sp(0x10000);
|
||||
reg_list.push_back(mips);
|
||||
|
||||
RegsMips64* mips64 = new RegsMips64;
|
||||
mips64->set_pc(0x2300);
|
||||
mips64->set_sp(0x10000);
|
||||
reg_list.push_back(mips64);
|
||||
|
||||
for (auto regs : reg_list) {
|
||||
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
|
||||
|
||||
|
@ -744,10 +756,12 @@ TEST_F(UnwinderTest, format_frame) {
|
|||
switch (regs->Arch()) {
|
||||
case ARCH_ARM:
|
||||
case ARCH_X86:
|
||||
case ARCH_MIPS:
|
||||
expected = " #00 pc 00001300 /system/fake/libc.so (Frame0+10)";
|
||||
break;
|
||||
case ARCH_ARM64:
|
||||
case ARCH_X86_64:
|
||||
case ARCH_MIPS64:
|
||||
expected = " #00 pc 0000000000001300 /system/fake/libc.so (Frame0+10)";
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -76,6 +76,12 @@ void DoUnwind(pid_t pid) {
|
|||
case unwindstack::ARCH_X86_64:
|
||||
printf("x86_64");
|
||||
break;
|
||||
case unwindstack::ARCH_MIPS:
|
||||
printf("mips");
|
||||
break;
|
||||
case unwindstack::ARCH_MIPS64:
|
||||
printf("mips64");
|
||||
break;
|
||||
default:
|
||||
printf("unknown\n");
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue