Added riscv and riscv64 support for Linux

Change-Id: I62cd157d00a87720db001072662a81d8eb9112b0
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3873291
Reviewed-by: Mike Frysinger <vapier@chromium.org>
This commit is contained in:
Iacopo Colonnelli
2022-09-09 09:53:29 +02:00
committed by Mike Frysinger
parent e059dad5ea
commit 28cf16bc34
37 changed files with 4901 additions and 48 deletions

View File

@@ -43,6 +43,14 @@ typedef MDRawContextARM RawContextCPU;
typedef MDRawContextARM64_Old RawContextCPU;
#elif defined(__mips__)
typedef MDRawContextMIPS RawContextCPU;
#elif defined(__riscv)
# if __riscv_xlen == 32
typedef MDRawContextRISCV RawContextCPU;
# elif __riscv_xlen == 64
typedef MDRawContextRISCV64 RawContextCPU;
# else
# error "Unexpected __riscv_xlen"
# endif
#else
#error "This code has not been ported to your platform yet."
#endif

View File

@@ -269,7 +269,74 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
out->float_save.fir = mcontext.fpc_eir;
#endif
}
#endif // __mips__
#elif defined(__riscv)
uintptr_t ThreadInfo::GetInstructionPointer() const {
return mcontext.__gregs[0];
}
void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
# if __riscv__xlen == 32
out->context_flags = MD_CONTEXT_RISCV_FULL;
# elif __riscv_xlen == 64
out->context_flags = MD_CONTEXT_RISCV64_FULL;
# else
# error "Unexpected __riscv_xlen"
# endif
out->pc = mcontext.__gregs[0];
out->ra = mcontext.__gregs[1];
out->sp = mcontext.__gregs[2];
out->gp = mcontext.__gregs[3];
out->tp = mcontext.__gregs[4];
out->t0 = mcontext.__gregs[5];
out->t1 = mcontext.__gregs[6];
out->t2 = mcontext.__gregs[7];
out->s0 = mcontext.__gregs[8];
out->s1 = mcontext.__gregs[9];
out->a0 = mcontext.__gregs[10];
out->a1 = mcontext.__gregs[11];
out->a2 = mcontext.__gregs[12];
out->a3 = mcontext.__gregs[13];
out->a4 = mcontext.__gregs[14];
out->a5 = mcontext.__gregs[15];
out->a6 = mcontext.__gregs[16];
out->a7 = mcontext.__gregs[17];
out->s2 = mcontext.__gregs[18];
out->s3 = mcontext.__gregs[19];
out->s4 = mcontext.__gregs[20];
out->s5 = mcontext.__gregs[21];
out->s6 = mcontext.__gregs[22];
out->s7 = mcontext.__gregs[23];
out->s8 = mcontext.__gregs[24];
out->s9 = mcontext.__gregs[25];
out->s10 = mcontext.__gregs[26];
out->s11 = mcontext.__gregs[27];
out->t3 = mcontext.__gregs[28];
out->t4 = mcontext.__gregs[29];
out->t5 = mcontext.__gregs[30];
out->t6 = mcontext.__gregs[31];
# if __riscv_flen == 32
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++)
out->float_save.regs[i] = mcontext.__fpregs.__f.__f[i];
out->float_save.fpcsr = mcontext.__fpregs.__f.__fcsr;
# elif __riscv_flen == 64
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++)
out->float_save.regs[i] = mcontext.__fpregs.__d.__f[i];
out->float_save.fpcsr = mcontext.__fpregs.__d.__fcsr;
# elif __riscv_flen == 128
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) {
out->float_save.regs[i].high = mcontext.__fpregs.__q.__f[2*i];
out->float_save.regs[i].low = mcontext.__fpregs.__q.__f[2*i+1];
}
out->float_save.fpcsr = mcontext.__fpregs.__q.__fcsr;
# else
# error "Unexpected __riscv_flen"
# endif
}
#endif // __riscv
void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
assert(gp_regs || size);
@@ -278,6 +345,11 @@ void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
*gp_regs = mcontext.gregs;
if (size)
*size = sizeof(mcontext.gregs);
#elif defined(__riscv)
if (gp_regs)
*gp_regs = mcontext.__gregs;
if (size)
*size = sizeof(mcontext.__gregs);
#else
if (gp_regs)
*gp_regs = &regs;
@@ -293,6 +365,25 @@ void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) {
*fp_regs = &mcontext.fpregs;
if (size)
*size = sizeof(mcontext.fpregs);
#elif defined(__riscv)
# if __riscv_flen == 32
if (fp_regs)
*fp_regs = &mcontext.__fpregs.__f.__f;
if (size)
*size = sizeof(mcontext.__fpregs.__f.__f);
# elif __riscv_flen == 64
if (fp_regs)
*fp_regs = &mcontext.__fpregs.__d.__f;
if (size)
*size = sizeof(mcontext.__fpregs.__d.__f);
# elif __riscv_flen == 128
if (fp_regs)
*fp_regs = &mcontext.__fpregs.__q.__f;
if (size)
*size = sizeof(mcontext.__fpregs.__q.__f);
# else
# error "Unexpected __riscv_flen"
# endif
#else
if (fp_regs)
*fp_regs = &fpregs;

View File

@@ -67,7 +67,7 @@ struct ThreadInfo {
// Use the structures defined in <sys/user.h>
struct user_regs_struct regs;
struct user_fpsimd_struct fpregs;
#elif defined(__mips__)
#elif defined(__mips__) || defined(__riscv)
// Use the structure defined in <sys/ucontext.h>.
mcontext_t mcontext;
#endif

View File

@@ -253,6 +253,75 @@ void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused.
#endif
}
#elif defined(__riscv)
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
return uc->uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP];
}
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_PC];
}
void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
# if __riscv__xlen == 32
out->context_flags = MD_CONTEXT_RISCV_FULL;
# elif __riscv_xlen == 64
out->context_flags = MD_CONTEXT_RISCV64_FULL;
# else
# error "Unexpected __riscv_xlen"
# endif
out->pc = uc->uc_mcontext.__gregs[0];
out->ra = uc->uc_mcontext.__gregs[1];
out->sp = uc->uc_mcontext.__gregs[2];
out->gp = uc->uc_mcontext.__gregs[3];
out->tp = uc->uc_mcontext.__gregs[4];
out->t0 = uc->uc_mcontext.__gregs[5];
out->t1 = uc->uc_mcontext.__gregs[6];
out->t2 = uc->uc_mcontext.__gregs[7];
out->s0 = uc->uc_mcontext.__gregs[8];
out->s1 = uc->uc_mcontext.__gregs[9];
out->a0 = uc->uc_mcontext.__gregs[10];
out->a1 = uc->uc_mcontext.__gregs[11];
out->a2 = uc->uc_mcontext.__gregs[12];
out->a3 = uc->uc_mcontext.__gregs[13];
out->a4 = uc->uc_mcontext.__gregs[14];
out->a5 = uc->uc_mcontext.__gregs[15];
out->a6 = uc->uc_mcontext.__gregs[16];
out->a7 = uc->uc_mcontext.__gregs[17];
out->s2 = uc->uc_mcontext.__gregs[18];
out->s3 = uc->uc_mcontext.__gregs[19];
out->s4 = uc->uc_mcontext.__gregs[20];
out->s5 = uc->uc_mcontext.__gregs[21];
out->s6 = uc->uc_mcontext.__gregs[22];
out->s7 = uc->uc_mcontext.__gregs[23];
out->s8 = uc->uc_mcontext.__gregs[24];
out->s9 = uc->uc_mcontext.__gregs[25];
out->s10 = uc->uc_mcontext.__gregs[26];
out->s11 = uc->uc_mcontext.__gregs[27];
out->t3 = uc->uc_mcontext.__gregs[28];
out->t4 = uc->uc_mcontext.__gregs[29];
out->t5 = uc->uc_mcontext.__gregs[30];
out->t6 = uc->uc_mcontext.__gregs[31];
# if __riscv_flen == 32
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++)
out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__f.__f[i];
out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__f.__fcsr;
# elif __riscv_flen == 64
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++)
out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__d.__f[i];
out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__d.__fcsr;
# elif __riscv_flen == 128
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) {
out->float_save.regs[i].high = uc->uc_mcontext.__fpregs.__q.__f[2*i];
out->float_save.regs[i].low = uc->uc_mcontext.__fpregs.__q.__f[2*i+1];
}
out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__q.__fcsr;
# endif
}
#endif
} // namespace google_breakpad

View File

@@ -461,9 +461,6 @@ bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) {
sizeof(g_crash_context_.float_state));
}
#elif GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE
// FP state is not part of user ABI on ARM Linux.
// In case of MIPS Linux FP state is already part of ucontext_t
// and 'float_state' is not a member of CrashContext.
ucontext_t* uc_ptr = (ucontext_t*)uc;
if (uc_ptr->uc_mcontext.fpregs) {
memcpy(&g_crash_context_.float_state, uc_ptr->uc_mcontext.fpregs,
@@ -701,7 +698,6 @@ bool ExceptionHandler::WriteMinidump() {
#endif
#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE && !defined(__aarch64__)
// FPU state is not part of ARM EABI ucontext_t.
memcpy(&context.float_state, context.context.uc_mcontext.fpregs,
sizeof(context.float_state));
#endif
@@ -725,8 +721,11 @@ bool ExceptionHandler::WriteMinidump() {
#elif defined(__mips__)
context.siginfo.si_addr =
reinterpret_cast<void*>(context.context.uc_mcontext.pc);
#elif defined(__riscv)
context.siginfo.si_addr =
reinterpret_cast<void*>(context.context.uc_mcontext.__gregs[REG_PC]);
#else
#error "This code has not been ported to your platform yet."
# error "This code has not been ported to your platform yet."
#endif
return GenerateDump(&context);

View File

@@ -43,7 +43,7 @@
#include "common/using_std_string.h"
#include "google_breakpad/common/minidump_format.h"
#if !defined(__ARM_EABI__) && !defined(__mips__)
#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
// FP state is not part of user ABI for Linux ARM.
// In case of MIPS and RISCV Linux FP state is already part of ucontext_t
// so 'float_state' is not required.

View File

@@ -335,9 +335,17 @@ class MicrodumpWriter {
const char kArch[] = "mips64";
# else
# error "This mips ABI is currently not supported (n32)"
#endif
# endif
#elif defined(__riscv)
# if __riscv_xlen == 32
const char kArch[] = "riscv32";
# elif __riscv_xlen == 64
const char kArch[] = "riscv64";
# else
# error "Unexpected __riscv_xlen"
# endif
#else
#error "This code has not been ported to your platform yet"
# error "This code has not been ported to your platform yet"
#endif
LogAppend("O ");

View File

@@ -111,8 +111,11 @@ bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
#elif defined(__mips__)
stack_pointer =
reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
#elif defined(__riscv)
stack_pointer = reinterpret_cast<uint8_t*>(
info->mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP]);
#else
#error "This code hasn't been ported to your platform yet."
# error "This code hasn't been ported to your platform yet."
#endif
info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer);
return true;
@@ -207,19 +210,22 @@ bool LinuxCoreDumper::EnumerateThreads() {
info.tgid = status->pr_pgrp;
info.ppid = status->pr_ppid;
#if defined(__mips__)
#if defined(__ANDROID__)
# if defined(__ANDROID__)
for (int i = EF_R0; i <= EF_R31; i++)
info.mcontext.gregs[i - EF_R0] = status->pr_reg[i];
#else // __ANDROID__
# else // __ANDROID__
for (int i = EF_REG0; i <= EF_REG31; i++)
info.mcontext.gregs[i - EF_REG0] = status->pr_reg[i];
#endif // __ANDROID__
# endif // __ANDROID__
info.mcontext.mdlo = status->pr_reg[EF_LO];
info.mcontext.mdhi = status->pr_reg[EF_HI];
info.mcontext.pc = status->pr_reg[EF_CP0_EPC];
#else // __mips__
#elif defined(__riscv)
memcpy(&info.mcontext.__gregs, status->pr_reg,
sizeof(info.mcontext.__gregs));
#else // __riscv
memcpy(&info.regs, status->pr_reg, sizeof(info.regs));
#endif // __mips__
#endif
if (first_thread) {
crash_thread_ = pid;
crash_signal_ = status->pr_info.si_signo;

View File

@@ -59,10 +59,12 @@ namespace google_breakpad {
// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
#if defined(__i386) || defined(__ARM_EABI__) || \
(defined(__mips__) && _MIPS_SIM == _ABIO32)
(defined(__mips__) && _MIPS_SIM == _ABIO32) || \
(defined(__riscv) && __riscv_xlen == 32)
typedef Elf32_auxv_t elf_aux_entry;
#elif defined(__x86_64) || defined(__aarch64__) || \
(defined(__mips__) && _MIPS_SIM != _ABIO32)
(defined(__mips__) && _MIPS_SIM != _ABIO32) || \
(defined(__riscv) && __riscv_xlen == 64)
typedef Elf64_auxv_t elf_aux_entry;
#endif

View File

@@ -50,6 +50,8 @@
#define TID_PTR_REGISTER "rcx"
#elif defined(__mips__)
#define TID_PTR_REGISTER "$1"
#elif defined(__riscv)
#define TID_PTR_REGISTER "x4"
#else
#error This test has not been ported to this platform.
#endif

View File

@@ -297,8 +297,11 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
#elif defined(__mips__)
stack_pointer =
reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
#elif defined(__riscv)
stack_pointer = reinterpret_cast<uint8_t*>(
info->mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP]);
#else
#error "This code hasn't been ported to your platform yet."
# error "This code hasn't been ported to your platform yet."
#endif
info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer);

View File

@@ -463,6 +463,9 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
#elif defined(__mips__)
pid_t* process_tid_location =
reinterpret_cast<pid_t*>(one_thread.mcontext.gregs[1]);
#elif defined(__riscv)
pid_t* process_tid_location =
reinterpret_cast<pid_t*>(one_thread.mcontext.__gregs[4]);
#else
#error This test has not been ported to this platform.
#endif
@@ -560,6 +563,8 @@ TEST_F(LinuxPtraceDumperTest, SanitizeStackCopy) {
uintptr_t heap_addr = thread_info.regs.rcx;
#elif defined(__mips__)
uintptr_t heap_addr = thread_info.mcontext.gregs[1];
#elif defined(__riscv)
uintptr_t heap_addr = thread_info.mcontext.__gregs[4];
#else
#error This test has not been ported to this platform.
#endif

View File

@@ -1137,9 +1137,7 @@ class MinidumpWriter {
sys_close(fd);
cpus_present.IntersectWith(cpus_possible);
int cpu_count = cpus_present.GetCount();
if (cpu_count > 255)
cpu_count = 255;
int cpu_count = std::min(255, cpus_present.GetCount());
sys_info->number_of_processors = static_cast<uint8_t>(cpu_count);
}
}
@@ -1255,6 +1253,59 @@ class MinidumpWriter {
sys_close(fd);
}
return true;
}
#elif defined(__riscv)
bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
// processor_architecture should always be set, do this first
# if __riscv_xlen == 32
sys_info->processor_architecture = MD_CPU_ARCHITECTURE_RISCV;
# elif __riscv_xlen == 64
sys_info->processor_architecture = MD_CPU_ARCHITECTURE_RISCV64;
# else
# error "Unexpected __riscv_xlen"
# endif
// /proc/cpuinfo is not readable under various sandboxed environments
// (e.g. Android services with the android:isolatedProcess attribute)
// prepare for this by setting default values now, which will be
// returned when this happens.
//
// Note: Bogus values are used to distinguish between failures (to
// read /sys and /proc files) and really badly configured kernels.
sys_info->number_of_processors = 0;
sys_info->processor_level = 0U;
sys_info->processor_revision = 42;
sys_info->cpu.other_cpu_info.processor_features[0] = 0;
sys_info->cpu.other_cpu_info.processor_features[1] = 0;
// Counting the number of CPUs involves parsing two sysfs files,
// because the content of /proc/cpuinfo will only mirror the number
// of 'online' cores, and thus will vary with time.
// See http://www.kernel.org/doc/Documentation/cputopology.txt
{
CpuSet cpus_present;
CpuSet cpus_possible;
int fd = sys_open("/sys/devices/system/cpu/present",
O_RDONLY | O_CLOEXEC, 0);
if (fd >= 0) {
cpus_present.ParseSysFile(fd);
sys_close(fd);
fd = sys_open("/sys/devices/system/cpu/possible",
O_RDONLY | O_CLOEXEC, 0);
if (fd >= 0) {
cpus_possible.ParseSysFile(fd);
sys_close(fd);
cpus_present.IntersectWith(cpus_possible);
int cpu_count = std::min(255, cpus_present.GetCount());
sys_info->number_of_processors = static_cast<uint8_t>(cpu_count);
}
}
}
return true;
}
#else

View File

@@ -716,6 +716,9 @@ TEST(MinidumpWriterTest, InvalidStackPointer) {
#elif defined(__mips__)
context.context.uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP] =
invalid_stack_pointer;
#elif defined(__riscv)
context.context.uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP] =
invalid_stack_pointer;
#else
# error "This code has not been ported to your platform yet."
#endif