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:
Douglas Leung 2017-11-08 10:53:53 +01:00 committed by Dejan Jovicevic
parent 84de4c0a89
commit 61b1a1ae77
23 changed files with 1256 additions and 12 deletions

View file

@ -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: [

View 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

View 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

View file

@ -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));

View 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

View 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

View file

@ -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
View 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

View 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, &regs_[MIPS64_REG_PC],
sizeof(uint64_t))) {
return false;
}
SetFromRaw();
return true;
}
} // namespace unwindstack

View 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

View 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
View 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

View 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

View file

@ -42,6 +42,8 @@ enum ArchEnum : uint8_t {
ARCH_ARM64,
ARCH_X86,
ARCH_X86_64,
ARCH_MIPS,
ARCH_MIPS64,
};
class Elf {

View file

@ -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

View 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

View 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

View file

@ -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) {

View file

@ -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) {

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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;