mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-25 22:30:49 +08:00
[riscv] Add RISC-V Linux support
Only RV64GC is supported. Bug: fuchsia:127655 Tested: `python build/run_tests.py` on RISC-V emulator Tested: Created minidump via self-induced crash on RISC-V emulator, ran through Breakpad stackwalker Change-Id: I713797cd623b0a758269048e01696cbce502ca6c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4581050 Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
656fc62589
commit
4f5dd67229
@ -637,6 +637,56 @@ struct MinidumpContextMIPS64 {
|
||||
uint64_t fir;
|
||||
};
|
||||
|
||||
//! \brief 64-bit RISCV-specific flags for
|
||||
//! MinidumpContextRISCV64::context_flags.
|
||||
enum MinidumpContextRISCV64Flags : uint32_t {
|
||||
//! \brief Identifies the context structure as RISCV64.
|
||||
kMinidumpContextRISCV64 = 0x08000000,
|
||||
|
||||
//! \brief Indicates the validity of integer registers.
|
||||
//!
|
||||
//! Registers 'pc' and `x1`-`x31` are valid.
|
||||
kMinidumpContextRISCV64Integer = kMinidumpContextRISCV64 | 0x00000001,
|
||||
|
||||
//! \brief Indicates the validity of floating point registers.
|
||||
//!
|
||||
//! Floating point registers `f0`-`f31` are valid.
|
||||
kMinidumpContextRISCV64FloatingPoint = kMinidumpContextRISCV64 | 0x00000002,
|
||||
|
||||
//! \brief Indicates the validity of all registers.
|
||||
kMinidumpContextRISCV64All = kMinidumpContextRISCV64Integer |
|
||||
kMinidumpContextRISCV64FloatingPoint,
|
||||
};
|
||||
|
||||
//! \brief A 64-bit RISC-V CPU context (register state) carried in a minidump
|
||||
//! file.
|
||||
//!
|
||||
//! This structure is versioned. Increment |kVersion| when changing this
|
||||
//! structure.
|
||||
struct MinidumpContextRISCV64 {
|
||||
|
||||
//! \brief The structure’s currently-defined version number.
|
||||
static constexpr uint32_t kVersion = 1;
|
||||
|
||||
//! \brief Indicates the validity of fields in this structure.
|
||||
uint32_t context_flags;
|
||||
|
||||
//! \brief The structure’s version number.
|
||||
uint32_t version;
|
||||
|
||||
//! \brief The program counter register.
|
||||
uint64_t pc;
|
||||
|
||||
//! \brief The integer registers, x1 through x31.
|
||||
uint64_t regs[31];
|
||||
|
||||
//! \brief The floating point registers.
|
||||
uint64_t fpregs[32];
|
||||
|
||||
//! \brief The floating point control and status register.
|
||||
uint32_t fcsr;
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_H_
|
||||
|
@ -102,6 +102,13 @@ MinidumpContextWriter::CreateFromSnapshot(const CPUContext* context_snapshot) {
|
||||
break;
|
||||
}
|
||||
|
||||
case kCPUArchitectureRISCV64: {
|
||||
context = std::make_unique<MinidumpContextRISCV64Writer>();
|
||||
reinterpret_cast<MinidumpContextRISCV64Writer*>(context.get())
|
||||
->InitializeFromSnapshot(context_snapshot->riscv64);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
LOG(ERROR) << "unknown context architecture "
|
||||
<< context_snapshot->architecture;
|
||||
@ -556,4 +563,42 @@ size_t MinidumpContextMIPS64Writer::ContextSize() const {
|
||||
return sizeof(context_);
|
||||
}
|
||||
|
||||
MinidumpContextRISCV64Writer::MinidumpContextRISCV64Writer()
|
||||
: MinidumpContextWriter(), context_() {
|
||||
context_.context_flags = kMinidumpContextRISCV64;
|
||||
context_.version = MinidumpContextRISCV64::kVersion;
|
||||
}
|
||||
|
||||
MinidumpContextRISCV64Writer::~MinidumpContextRISCV64Writer() = default;
|
||||
|
||||
void MinidumpContextRISCV64Writer::InitializeFromSnapshot(
|
||||
const CPUContextRISCV64* context_snapshot) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
DCHECK_EQ(context_.context_flags, kMinidumpContextRISCV64);
|
||||
|
||||
context_.context_flags = kMinidumpContextRISCV64All;
|
||||
context_.version = MinidumpContextRISCV64::kVersion;
|
||||
context_.pc = context_snapshot->pc;
|
||||
|
||||
static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs),
|
||||
"GPRs size mismatch");
|
||||
memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
|
||||
|
||||
static_assert(sizeof(context_.fpregs) == sizeof(context_snapshot->fpregs),
|
||||
"FPRs size mismatch");
|
||||
memcpy(context_.fpregs, context_snapshot->fpregs, sizeof(context_.fpregs));
|
||||
context_.fcsr = context_snapshot->fcsr;
|
||||
}
|
||||
|
||||
bool MinidumpContextRISCV64Writer::WriteObject(
|
||||
FileWriterInterface* file_writer) {
|
||||
DCHECK_EQ(state(), kStateWritable);
|
||||
return file_writer->Write(&context_, sizeof(context_));
|
||||
}
|
||||
|
||||
size_t MinidumpContextRISCV64Writer::ContextSize() const {
|
||||
DCHECK_GE(state(), kStateFrozen);
|
||||
return sizeof(context_);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -369,6 +369,50 @@ class MinidumpContextMIPS64Writer final : public MinidumpContextWriter {
|
||||
MinidumpContextMIPS64 context_;
|
||||
};
|
||||
|
||||
//! \brief The writer for a MinidumpContextRISCV64 structure in a minidump file.
|
||||
class MinidumpContextRISCV64Writer final : public MinidumpContextWriter {
|
||||
public:
|
||||
MinidumpContextRISCV64Writer();
|
||||
|
||||
MinidumpContextRISCV64Writer(const MinidumpContextRISCV64Writer&) = delete;
|
||||
MinidumpContextRISCV64Writer& operator=(const MinidumpContextRISCV64Writer&) =
|
||||
delete;
|
||||
|
||||
~MinidumpContextRISCV64Writer() override;
|
||||
|
||||
//! \brief Initializes the MinidumpContextRISCV64 based on \a
|
||||
//! context_snapshot.
|
||||
//!
|
||||
//! \param[in] context_snapshot The context snapshot to use as source data.
|
||||
//!
|
||||
//! \note Valid in #kStateMutable. No mutation of context() may be done before
|
||||
//! calling this method, and it is not normally necessary to alter
|
||||
//! context() after calling this method.
|
||||
void InitializeFromSnapshot(const CPUContextRISCV64* context_snapshot);
|
||||
|
||||
//! \brief Returns a pointer to the context structure that this object will
|
||||
//! write.
|
||||
//!
|
||||
//! \attention This returns a non-`const` pointer to this object’s private
|
||||
//! data so that a caller can populate the context structure directly.
|
||||
//! This is done because providing setter interfaces to each field in the
|
||||
//! context structure would be unwieldy and cumbersome. Care must be taken
|
||||
//! to populate the context structure correctly. The context structure
|
||||
//! must only be modified while this object is in the #kStateMutable
|
||||
//! state.
|
||||
MinidumpContextRISCV64* context() { return &context_; }
|
||||
|
||||
protected:
|
||||
// MinidumpWritable:
|
||||
bool WriteObject(FileWriterInterface* file_writer) override;
|
||||
|
||||
// MinidumpContextWriter:
|
||||
size_t ContextSize() const override;
|
||||
|
||||
private:
|
||||
MinidumpContextRISCV64 context_;
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_
|
||||
|
@ -143,6 +143,49 @@ TYPED_TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(MinidumpContextWriter, MinidumpContextRISCV64Writer) {
|
||||
{
|
||||
// Make sure that a heap-allocated context writer has the proper alignment,
|
||||
// because it may be nonstandard.
|
||||
auto context_writer = std::make_unique<MinidumpContextRISCV64Writer>();
|
||||
EXPECT_EQ(reinterpret_cast<uintptr_t>(context_writer.get()) &
|
||||
(alignof(MinidumpContextRISCV64Writer) - 1),
|
||||
0u);
|
||||
}
|
||||
|
||||
StringFile string_file;
|
||||
|
||||
{
|
||||
// Make sure that a context writer that’s untouched writes a zeroed-out
|
||||
// context.
|
||||
SCOPED_TRACE("zero");
|
||||
|
||||
EmptyContextTest<MinidumpContextRISCV64Writer,
|
||||
MinidumpContextRISCV64,
|
||||
TypeParam>(ExpectMinidumpContextRISCV64);
|
||||
}
|
||||
|
||||
{
|
||||
SCOPED_TRACE("nonzero");
|
||||
|
||||
string_file.Reset();
|
||||
constexpr uint32_t kSeed = 0x808664;
|
||||
|
||||
MinidumpContextRISCV64Writer context_writer;
|
||||
InitializeMinidumpContextRISCV64(context_writer.context(), kSeed);
|
||||
|
||||
EXPECT_TRUE(context_writer.WriteEverything(&string_file));
|
||||
ASSERT_EQ(string_file.string().size(), sizeof(MinidumpContextRISCV64));
|
||||
|
||||
const MinidumpContextRISCV64* observed =
|
||||
MinidumpWritableAtRVA<MinidumpContextRISCV64>(string_file.string(),
|
||||
TypeParam(0));
|
||||
ASSERT_TRUE(observed);
|
||||
|
||||
ExpectMinidumpContextRISCV64(kSeed, observed, false);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Writer, typename Context, typename RVAType>
|
||||
void FromSnapshotTest(const CPUContext& snapshot_context,
|
||||
void (*expect_context)(uint32_t, const Context*, bool),
|
||||
@ -268,6 +311,23 @@ TYPED_TEST(MinidumpContextWriter, MIPS64_FromSnapshot) {
|
||||
TypeParam>(context, ExpectMinidumpContextMIPS64, kSeed);
|
||||
}
|
||||
|
||||
TYPED_TEST(MinidumpContextWriter, RISCV64_Zeros) {
|
||||
EmptyContextTest<MinidumpContextRISCV64Writer,
|
||||
MinidumpContextRISCV64,
|
||||
TypeParam>(ExpectMinidumpContextRISCV64);
|
||||
}
|
||||
|
||||
TYPED_TEST(MinidumpContextWriter, RISCV64_FromSnapshot) {
|
||||
constexpr uint32_t kSeed = 64;
|
||||
CPUContextRISCV64 context_riscv64;
|
||||
CPUContext context;
|
||||
context.riscv64 = &context_riscv64;
|
||||
InitializeCPUContextRISCV64(&context, kSeed);
|
||||
FromSnapshotTest<MinidumpContextRISCV64Writer,
|
||||
MinidumpContextRISCV64,
|
||||
TypeParam>(context, ExpectMinidumpContextRISCV64, kSeed);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -210,6 +210,9 @@ enum MinidumpCPUArchitecture : uint16_t {
|
||||
//! \deprecated Use #kMinidumpCPUArchitectureARM64 instead.
|
||||
kMinidumpCPUArchitectureARM64Breakpad = 0x8003,
|
||||
|
||||
//! \brief Used by Breakpad for 64-bit RISC-V.
|
||||
kMinidumpCPUArchitectureRISCV64Breakpad = 0x8006,
|
||||
|
||||
//! \brief Unknown CPU architecture.
|
||||
kMinidumpCPUArchitectureUnknown = PROCESSOR_ARCHITECTURE_UNKNOWN,
|
||||
};
|
||||
|
@ -175,6 +175,8 @@ std::string MinidumpMiscInfoDebugBuildString() {
|
||||
static constexpr char kCPU[] = "mips";
|
||||
#elif defined(ARCH_CPU_MIPS64EL)
|
||||
static constexpr char kCPU[] = "mips64";
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
static constexpr char kCPU[] = "riscv64";
|
||||
#else
|
||||
#error define kCPU for this CPU
|
||||
#endif
|
||||
|
@ -132,6 +132,9 @@ void MinidumpSystemInfoWriter::InitializeFromSnapshot(
|
||||
case kCPUArchitectureARM64:
|
||||
cpu_architecture = kMinidumpCPUArchitectureARM64;
|
||||
break;
|
||||
case kCPUArchitectureRISCV64:
|
||||
cpu_architecture = kMinidumpCPUArchitectureRISCV64Breakpad;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
cpu_architecture = kMinidumpCPUArchitectureUnknown;
|
||||
|
@ -272,6 +272,31 @@ void InitializeMinidumpContextMIPS64(MinidumpContextMIPS64* context,
|
||||
context->dsp_control = value++;
|
||||
}
|
||||
|
||||
void InitializeMinidumpContextRISCV64(MinidumpContextRISCV64* context,
|
||||
uint32_t seed) {
|
||||
if (seed == 0) {
|
||||
memset(context, 0, sizeof(*context));
|
||||
context->context_flags = kMinidumpContextRISCV64;
|
||||
context->version = MinidumpContextRISCV64::kVersion;
|
||||
return;
|
||||
}
|
||||
|
||||
context->context_flags = kMinidumpContextRISCV64All;
|
||||
context->version = MinidumpContextRISCV64::kVersion;
|
||||
|
||||
uint32_t value = seed;
|
||||
|
||||
context->pc = value++;
|
||||
for (size_t index = 0; index < std::size(context->regs); ++index) {
|
||||
context->regs[index] = value++;
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < std::size(context->fpregs); ++index) {
|
||||
context->fpregs[index] = value++;
|
||||
}
|
||||
context->fcsr = value++;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Using Google Test assertions, compares |expected| to |observed|. This is
|
||||
@ -601,5 +626,24 @@ void ExpectMinidumpContextMIPS64(uint32_t expect_seed,
|
||||
EXPECT_EQ(observed->dsp_control, expected.dsp_control);
|
||||
}
|
||||
|
||||
void ExpectMinidumpContextRISCV64(uint32_t expect_seed,
|
||||
const MinidumpContextRISCV64* observed,
|
||||
bool snapshot) {
|
||||
MinidumpContextRISCV64 expected;
|
||||
InitializeMinidumpContextRISCV64(&expected, expect_seed);
|
||||
|
||||
EXPECT_EQ(observed->context_flags, expected.context_flags);
|
||||
EXPECT_EQ(observed->version, expected.version);
|
||||
|
||||
for (size_t index = 0; index < std::size(expected.regs); ++index) {
|
||||
EXPECT_EQ(observed->regs[index], expected.regs[index]);
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < std::size(expected.fpregs); ++index) {
|
||||
EXPECT_EQ(observed->fpregs[index], expected.fpregs[index]);
|
||||
}
|
||||
EXPECT_EQ(observed->fcsr, expected.fcsr);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -47,6 +47,8 @@ void InitializeMinidumpContextARM64(MinidumpContextARM64* context,
|
||||
void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context, uint32_t seed);
|
||||
void InitializeMinidumpContextMIPS64(MinidumpContextMIPS* context,
|
||||
uint32_t seed);
|
||||
void InitializeMinidumpContextRISCV64(MinidumpContextRISCV64* context,
|
||||
uint32_t seed);
|
||||
//! \}
|
||||
|
||||
//! \brief Verifies, via Google Test assertions, that a context structure
|
||||
@ -85,6 +87,9 @@ void ExpectMinidumpContextMIPS(uint32_t expect_seed,
|
||||
void ExpectMinidumpContextMIPS64(uint32_t expect_seed,
|
||||
const MinidumpContextMIPS64* observed,
|
||||
bool snapshot);
|
||||
void ExpectMinidumpContextRISCV64(uint32_t expect_seed,
|
||||
const MinidumpContextRISCV64* observed,
|
||||
bool snapshot);
|
||||
//! \}
|
||||
|
||||
} // namespace test
|
||||
|
@ -117,6 +117,11 @@ void CaptureMemory::PointedToByContext(const CPUContext& context,
|
||||
for (size_t i = 0; i < std::size(context.mipsel->regs); ++i) {
|
||||
MaybeCaptureMemoryAround(delegate, context.mipsel->regs[i]);
|
||||
}
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
MaybeCaptureMemoryAround(delegate, context.riscv64->pc);
|
||||
for (size_t i = 0; i < std::size(context.riscv64->regs); ++i) {
|
||||
MaybeCaptureMemoryAround(delegate, context.riscv64->regs[i]);
|
||||
}
|
||||
#else
|
||||
#error Port.
|
||||
#endif
|
||||
|
@ -43,7 +43,10 @@ enum CPUArchitecture {
|
||||
kCPUArchitectureMIPSEL,
|
||||
|
||||
//! \brief 64-bit MIPSEL.
|
||||
kCPUArchitectureMIPS64EL
|
||||
kCPUArchitectureMIPS64EL,
|
||||
|
||||
//! \brief 64-bit RISC-V.
|
||||
kCPUArchitectureRISCV64,
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <iterator>
|
||||
|
||||
#include "base/notreached.h"
|
||||
#include "cpu_architecture.h"
|
||||
#include "util/misc/arraysize.h"
|
||||
#include "util/misc/implicit_cast.h"
|
||||
|
||||
@ -170,6 +171,8 @@ uint64_t CPUContext::InstructionPointer() const {
|
||||
return arm->pc;
|
||||
case kCPUArchitectureARM64:
|
||||
return arm64->pc;
|
||||
case kCPUArchitectureRISCV64:
|
||||
return riscv64->pc;
|
||||
default:
|
||||
NOTREACHED();
|
||||
return ~0ull;
|
||||
@ -186,6 +189,8 @@ uint64_t CPUContext::StackPointer() const {
|
||||
return arm->sp;
|
||||
case kCPUArchitectureARM64:
|
||||
return arm64->sp;
|
||||
case kCPUArchitectureRISCV64:
|
||||
return riscv64->regs[1];
|
||||
default:
|
||||
NOTREACHED();
|
||||
return ~0ull;
|
||||
@ -226,6 +231,7 @@ bool CPUContext::Is64Bit() const {
|
||||
case kCPUArchitectureX86_64:
|
||||
case kCPUArchitectureARM64:
|
||||
case kCPUArchitectureMIPS64EL:
|
||||
case kCPUArchitectureRISCV64:
|
||||
return true;
|
||||
case kCPUArchitectureX86:
|
||||
case kCPUArchitectureARM:
|
||||
|
@ -362,6 +362,15 @@ struct CPUContextMIPS64 {
|
||||
uint64_t fir;
|
||||
};
|
||||
|
||||
//! \brief A context structure carrying RISCV64 CPU state.
|
||||
struct CPUContextRISCV64 {
|
||||
uint64_t pc;
|
||||
uint64_t regs[31];
|
||||
|
||||
uint64_t fpregs[32];
|
||||
uint32_t fcsr;
|
||||
};
|
||||
|
||||
//! \brief A context structure capable of carrying the context of any supported
|
||||
//! CPU architecture.
|
||||
struct CPUContext {
|
||||
@ -402,6 +411,7 @@ struct CPUContext {
|
||||
CPUContextARM64* arm64;
|
||||
CPUContextMIPS* mipsel;
|
||||
CPUContextMIPS64* mips64;
|
||||
CPUContextRISCV64* riscv64;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -733,8 +733,11 @@ bool ElfImageReader::GetAddressFromDynamicArray(uint64_t tag,
|
||||
if (!dynamic_array_->GetValue(tag, log, address)) {
|
||||
return false;
|
||||
}
|
||||
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
|
||||
// The GNU loader updates the dynamic array according to the load bias.
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA) || \
|
||||
(defined(__GLIBC__) && defined(ARCH_CPU_RISCV64))
|
||||
// The GNU loader updates the dynamic array according to the load bias (except
|
||||
// for RISC-V: https://sourceware.org/bugzilla/show_bug.cgi?id=24484).
|
||||
// The Android and Fuchsia loaders only update the debug address.
|
||||
if (tag != DT_DEBUG) {
|
||||
*address += GetLoadBias();
|
||||
|
@ -266,6 +266,21 @@ void InitializeCPUContextARM64_OnlyFPSIMD(
|
||||
context->fpcr = float_context.fpcr;
|
||||
}
|
||||
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
|
||||
void InitializeCPUContextRISCV64(const ThreadContext::t64_t& thread_context,
|
||||
const FloatContext::f64_t& float_context,
|
||||
CPUContextRISCV64* context) {
|
||||
context->pc = thread_context.pc;
|
||||
|
||||
static_assert(sizeof(context->regs) == sizeof(thread_context.regs));
|
||||
memcpy(context->regs, thread_context.regs, sizeof(context->regs));
|
||||
|
||||
static_assert(sizeof(context->fpregs) == sizeof(float_context.fpregs));
|
||||
memcpy(context->fpregs, float_context.fpregs, sizeof(context->fpregs));
|
||||
context->fcsr = float_context.fcsr;
|
||||
}
|
||||
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
|
||||
} // namespace internal
|
||||
|
@ -174,6 +174,20 @@ void InitializeCPUContextMIPS(
|
||||
|
||||
#endif // ARCH_CPU_MIPS_FAMILY || DOXYGEN
|
||||
|
||||
#if defined(ARCH_CPU_RISCV64) || DOXYGEN
|
||||
|
||||
//! \brief Initializes a CPUContextRISCV64 structure from native context
|
||||
//! structures on Linux.
|
||||
//!
|
||||
//! \param[in] thread_context The native thread context.
|
||||
//! \param[in] float_context The native float context.
|
||||
//! \param[out] context The CPUContextRISCV64 structure to initialize.
|
||||
void InitializeCPUContextRISCV64(const ThreadContext::t64_t& thread_context,
|
||||
const FloatContext::f64_t& float_context,
|
||||
CPUContextRISCV64* context);
|
||||
|
||||
#endif // ARCH_CPU_RISCV64 || DOXYGEN
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
||||
|
||||
|
@ -325,6 +325,48 @@ bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
|
||||
reader, context_address, context_.mips64);
|
||||
}
|
||||
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
|
||||
static bool ReadContext(ProcessReaderLinux* reader,
|
||||
LinuxVMAddress context_address,
|
||||
typename ContextTraits64::CPUContext* dest_context) {
|
||||
const ProcessMemory* memory = reader->Memory();
|
||||
|
||||
LinuxVMAddress gregs_address = context_address +
|
||||
offsetof(UContext<ContextTraits64>, mcontext) +
|
||||
offsetof(MContext64, regs);
|
||||
|
||||
typename ContextTraits64::SignalThreadContext thread_context;
|
||||
if (!memory->Read(gregs_address, sizeof(thread_context), &thread_context)) {
|
||||
LOG(ERROR) << "Couldn't read gregs";
|
||||
return false;
|
||||
}
|
||||
|
||||
LinuxVMAddress fpregs_address =
|
||||
context_address + offsetof(UContext<ContextTraits64>, mcontext) +
|
||||
offsetof(MContext64, fpregs);
|
||||
|
||||
typename ContextTraits64::SignalFloatContext fp_context;
|
||||
if (!memory->Read(fpregs_address, sizeof(fp_context), &fp_context)) {
|
||||
LOG(ERROR) << "Couldn't read fpregs";
|
||||
return false;
|
||||
}
|
||||
|
||||
InitializeCPUContextRISCV64(thread_context, fp_context, dest_context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
|
||||
ProcessReaderLinux* reader,
|
||||
LinuxVMAddress context_address) {
|
||||
context_.architecture = kCPUArchitectureRISCV64;
|
||||
context_.riscv64 = &context_union_.riscv64;
|
||||
|
||||
return internal::ReadContext(reader, context_address, context_.riscv64);
|
||||
}
|
||||
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
|
||||
bool ExceptionSnapshotLinux::Initialize(
|
||||
@ -355,10 +397,12 @@ bool ExceptionSnapshotLinux::Initialize(
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
#if !defined(ARCH_CPU_RISCV64)
|
||||
if (!ReadContext<ContextTraits32>(process_reader, context_address) ||
|
||||
!ReadSiginfo<Traits32>(process_reader, siginfo_address)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CaptureMemoryDelegateLinux capture_memory_delegate(
|
||||
|
@ -89,6 +89,8 @@ class ExceptionSnapshotLinux final : public ExceptionSnapshot {
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
CPUContextMIPS mipsel;
|
||||
CPUContextMIPS64 mips64;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
CPUContextRISCV64 riscv64;
|
||||
#endif
|
||||
} context_union_;
|
||||
CPUContext context_;
|
||||
|
@ -297,6 +297,34 @@ void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) {
|
||||
#undef CPU_ARCH_NAME
|
||||
}
|
||||
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
using NativeCPUContext = ucontext_t;
|
||||
|
||||
void InitializeContext(NativeCPUContext* context) {
|
||||
for (size_t reg = 0; reg < std::size(context->uc_mcontext.__gregs); ++reg) {
|
||||
context->uc_mcontext.__gregs[reg] = reg;
|
||||
}
|
||||
|
||||
memset(&context->uc_mcontext.__fpregs,
|
||||
44,
|
||||
sizeof(context->uc_mcontext.__fpregs));
|
||||
}
|
||||
|
||||
void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) {
|
||||
EXPECT_EQ(actual.architecture, kCPUArchitectureRISCV64);
|
||||
|
||||
EXPECT_EQ(actual.riscv64->pc, expected.uc_mcontext.__gregs[0]);
|
||||
|
||||
for (size_t reg = 0; reg < std::size(actual.riscv64->regs); ++reg) {
|
||||
EXPECT_EQ(actual.riscv64->regs[reg], expected.uc_mcontext.__gregs[reg + 1]);
|
||||
}
|
||||
|
||||
EXPECT_EQ(memcmp(&actual.riscv64->fpregs,
|
||||
&expected.uc_mcontext.__fpregs,
|
||||
sizeof(actual.riscv64->fpregs)),
|
||||
0);
|
||||
}
|
||||
|
||||
#else
|
||||
#error Port.
|
||||
#endif
|
||||
|
@ -127,6 +127,8 @@ void ProcessReaderLinux::Thread::InitializeStack(ProcessReaderLinux* reader) {
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
stack_pointer = reader->Is64Bit() ? thread_info.thread_context.t64.regs[29]
|
||||
: thread_info.thread_context.t32.regs[29];
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
stack_pointer = thread_info.thread_context.t64.regs[1];
|
||||
#else
|
||||
#error Port.
|
||||
#endif
|
||||
|
@ -422,6 +422,40 @@ static_assert(offsetof(UContext<ContextTraits64>, mcontext.fpregs) ==
|
||||
"context offset mismatch");
|
||||
#endif
|
||||
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
|
||||
struct ContextTraits64 : public Traits64 {
|
||||
using SignalThreadContext = ThreadContext::t64_t;
|
||||
using SignalFloatContext = FloatContext::f64_t;
|
||||
using CPUContext = CPUContextRISCV64;
|
||||
};
|
||||
|
||||
struct MContext64 {
|
||||
ThreadContext::t64_t regs;
|
||||
FloatContext::f64_t fpregs;
|
||||
};
|
||||
|
||||
template <typename Traits>
|
||||
struct UContext {
|
||||
typename Traits::ULong flags;
|
||||
typename Traits::Address link;
|
||||
SignalStack<Traits> stack;
|
||||
Sigset<Traits> sigmask;
|
||||
char alignment_padding_[8];
|
||||
char padding[128 - sizeof(Sigset<Traits>)];
|
||||
MContext64 mcontext;
|
||||
};
|
||||
|
||||
static_assert(offsetof(UContext<ContextTraits64>, mcontext) ==
|
||||
offsetof(ucontext_t, uc_mcontext),
|
||||
"context offset mismatch");
|
||||
static_assert(offsetof(UContext<ContextTraits64>, mcontext.regs) ==
|
||||
offsetof(ucontext_t, uc_mcontext.__gregs),
|
||||
"context offset mismatch");
|
||||
static_assert(offsetof(UContext<ContextTraits64>, mcontext.fpregs) ==
|
||||
offsetof(ucontext_t, uc_mcontext.__fpregs),
|
||||
"context offset mismatch");
|
||||
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
|
@ -205,6 +205,8 @@ CPUArchitecture SystemSnapshotLinux::GetCPUArchitecture() const {
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
return process_reader_->Is64Bit() ? kCPUArchitectureMIPS64EL
|
||||
: kCPUArchitectureMIPSEL;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
return kCPUArchitectureRISCV64;
|
||||
#else
|
||||
#error port to your architecture
|
||||
#endif
|
||||
@ -220,6 +222,9 @@ uint32_t SystemSnapshotLinux::CPURevision() const {
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
// Not implementable on MIPS
|
||||
return 0;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
// Not implemented
|
||||
return 0;
|
||||
#else
|
||||
#error port to your architecture
|
||||
#endif
|
||||
@ -240,6 +245,9 @@ std::string SystemSnapshotLinux::CPUVendor() const {
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
// Not implementable on MIPS
|
||||
return std::string();
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
// Not implemented
|
||||
return std::string();
|
||||
#else
|
||||
#error port to your architecture
|
||||
#endif
|
||||
@ -373,6 +381,9 @@ bool SystemSnapshotLinux::NXEnabled() const {
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
// Not implementable on MIPS
|
||||
return false;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
// Not implemented
|
||||
return false;
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
|
@ -110,6 +110,13 @@ bool WriteTestModule(const base::FilePath& module_path,
|
||||
module.ehdr.e_machine = EM_AARCH64;
|
||||
#elif defined(ARCH_CPU_MIPSEL) || defined(ARCH_CPU_MIPS64EL)
|
||||
module.ehdr.e_machine = EM_MIPS;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
module.ehdr.e_machine = EM_RISCV;
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_CPU_RISCV64)
|
||||
// Crashpad supports RV64GC
|
||||
module.ehdr.e_flags = EF_RISCV_RVC | EF_RISCV_FLOAT_ABI_DOUBLE;
|
||||
#endif
|
||||
|
||||
module.ehdr.e_version = EV_CURRENT;
|
||||
|
@ -190,6 +190,12 @@ bool ThreadSnapshotLinux::Initialize(
|
||||
thread.thread_info.float_context.f32,
|
||||
context_.mipsel);
|
||||
}
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
context_.architecture = kCPUArchitectureRISCV64;
|
||||
context_.riscv64 = &context_union_.riscv64;
|
||||
InitializeCPUContextRISCV64(thread.thread_info.thread_context.t64,
|
||||
thread.thread_info.float_context.f64,
|
||||
context_.riscv64);
|
||||
#else
|
||||
#error Port.
|
||||
#endif
|
||||
|
@ -74,6 +74,8 @@ class ThreadSnapshotLinux final : public ThreadSnapshot {
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
CPUContextMIPS mipsel;
|
||||
CPUContextMIPS64 mips64;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
CPUContextRISCV64 riscv64;
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
|
@ -266,6 +266,33 @@ bool MinidumpContextConverter::Initialize(
|
||||
context_.mips64->fir = src->fir;
|
||||
|
||||
memcpy(&context_.mips64->fpregs, &src->fpregs, sizeof(src->fpregs));
|
||||
} else if (context_.architecture ==
|
||||
CPUArchitecture::kCPUArchitectureRISCV64) {
|
||||
context_memory_.resize(sizeof(CPUContextRISCV64));
|
||||
context_.riscv64 =
|
||||
reinterpret_cast<CPUContextRISCV64*>(context_memory_.data());
|
||||
const MinidumpContextRISCV64* src =
|
||||
reinterpret_cast<const MinidumpContextRISCV64*>(
|
||||
minidump_context.data());
|
||||
if (minidump_context.size() < sizeof(MinidumpContextRISCV64)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(src->context_flags & kMinidumpContextRISCV64)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
context_.riscv64->pc = src->pc;
|
||||
|
||||
static_assert(sizeof(context_.riscv64->regs) == sizeof(src->regs),
|
||||
"GPR size mismatch");
|
||||
memcpy(&context_.riscv64->regs, &src->regs, sizeof(src->regs));
|
||||
|
||||
static_assert(sizeof(context_.riscv64->fpregs) == sizeof(src->fpregs),
|
||||
"FPR size mismatch");
|
||||
memcpy(&context_.riscv64->fpregs, &src->fpregs, sizeof(src->fpregs));
|
||||
|
||||
context_.riscv64->fcsr = src->fcsr;
|
||||
} else {
|
||||
// Architecture is listed as "unknown".
|
||||
DLOG(ERROR) << "Unknown architecture";
|
||||
|
@ -68,6 +68,8 @@ CPUArchitecture SystemSnapshotMinidump::GetCPUArchitecture() const {
|
||||
case kMinidumpCPUArchitectureMIPS:
|
||||
return kCPUArchitectureMIPSEL;
|
||||
// No word on how MIPS64 is signalled
|
||||
case kMinidumpCPUArchitectureRISCV64Breakpad:
|
||||
return kCPUArchitectureRISCV64;
|
||||
|
||||
default:
|
||||
return CPUArchitecture::kCPUArchitectureUnknown;
|
||||
|
@ -295,5 +295,27 @@ void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed) {
|
||||
mips64->dsp_control = value++;
|
||||
}
|
||||
|
||||
void InitializeCPUContextRISCV64(CPUContext* context, uint32_t seed) {
|
||||
context->architecture = kCPUArchitectureRISCV64;
|
||||
CPUContextRISCV64* riscv64 = context->riscv64;
|
||||
|
||||
if (seed == 0) {
|
||||
memset(riscv64, 0, sizeof(*riscv64));
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t value = seed;
|
||||
|
||||
riscv64->pc = value++;
|
||||
for (size_t index = 0; index < std::size(riscv64->regs); ++index) {
|
||||
riscv64->regs[index] = value++;
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < std::size(riscv64->fpregs); ++index) {
|
||||
riscv64->fpregs[index] = value++;
|
||||
}
|
||||
riscv64->fcsr = value++;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -63,6 +63,7 @@ void InitializeCPUContextARM(CPUContext* context, uint32_t seed);
|
||||
void InitializeCPUContextARM64(CPUContext* context, uint32_t seed);
|
||||
void InitializeCPUContextMIPS(CPUContext* context, uint32_t seed);
|
||||
void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed);
|
||||
void InitializeCPUContextRISCV64(CPUContext* context, uint32_t seed);
|
||||
//! \}
|
||||
|
||||
} // namespace test
|
||||
|
@ -49,6 +49,8 @@ LinuxVMAddress GetTLS() {
|
||||
: "=r"(tls)
|
||||
:
|
||||
: "$3");
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
asm("mv %0, tp" : "=r"(tls));
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_ARMEL
|
||||
|
@ -96,10 +96,15 @@ void TestAgainstCloneOrSelf(pid_t pid) {
|
||||
|
||||
ProcessMemoryLinux memory(&connection);
|
||||
|
||||
// AT_PLATFORM is null for RISC-V:
|
||||
// https://elixir.bootlin.com/linux/v6.4-rc4/C/ident/ELF_PLATFORM
|
||||
#if !defined(ARCH_CPU_RISCV64)
|
||||
LinuxVMAddress platform_addr;
|
||||
ASSERT_TRUE(aux.GetValue(AT_PLATFORM, &platform_addr));
|
||||
std::string platform;
|
||||
ASSERT_TRUE(memory.ReadCStringSizeLimited(platform_addr, 10, &platform));
|
||||
#endif // ARCH_CPU_RISCV64
|
||||
|
||||
#if defined(ARCH_CPU_X86)
|
||||
EXPECT_STREQ(platform.c_str(), "i686");
|
||||
#elif defined(ARCH_CPU_X86_64)
|
||||
|
@ -398,6 +398,37 @@ bool GetThreadArea64(pid_t tid,
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
|
||||
bool GetFloatingPointRegisters64(pid_t tid,
|
||||
FloatContext* context,
|
||||
bool can_log) {
|
||||
iovec iov;
|
||||
iov.iov_base = context;
|
||||
iov.iov_len = sizeof(*context);
|
||||
if (ptrace(
|
||||
PTRACE_GETREGSET, tid, reinterpret_cast<void*>(NT_PRFPREG), &iov) !=
|
||||
0) {
|
||||
PLOG_IF(ERROR, can_log) << "ptrace";
|
||||
return false;
|
||||
}
|
||||
if (iov.iov_len != sizeof(context->f64)) {
|
||||
LOG_IF(ERROR, can_log) << "Unexpected registers size " << iov.iov_len
|
||||
<< " != " << sizeof(context->f64);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetThreadArea64(pid_t tid,
|
||||
const ThreadContext& context,
|
||||
LinuxVMAddress* address,
|
||||
bool can_log) {
|
||||
// Thread pointer register
|
||||
*address = context.t64.regs[3];
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
@ -426,6 +457,7 @@ size_t GetGeneralPurposeRegistersAndLength(pid_t tid,
|
||||
return iov.iov_len;
|
||||
}
|
||||
|
||||
#if !defined(ARCH_CPU_RISCV64)
|
||||
bool GetGeneralPurposeRegisters32(pid_t tid,
|
||||
ThreadContext* context,
|
||||
bool can_log) {
|
||||
@ -437,6 +469,7 @@ bool GetGeneralPurposeRegisters32(pid_t tid,
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GetGeneralPurposeRegisters64(pid_t tid,
|
||||
ThreadContext* context,
|
||||
@ -500,12 +533,16 @@ bool Ptracer::GetThreadInfo(pid_t tid, ThreadInfo* info) {
|
||||
can_log_);
|
||||
}
|
||||
|
||||
#if !defined(ARCH_CPU_RISCV64)
|
||||
return GetGeneralPurposeRegisters32(tid, &info->thread_context, can_log_) &&
|
||||
GetFloatingPointRegisters32(tid, &info->float_context, can_log_) &&
|
||||
GetThreadArea32(tid,
|
||||
info->thread_context,
|
||||
&info->thread_specific_data_address,
|
||||
can_log_);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t Ptracer::ReadUpTo(pid_t pid,
|
||||
|
@ -29,6 +29,11 @@
|
||||
#include <android/api-level.h>
|
||||
#endif
|
||||
|
||||
// x86_64 has compilation errors if asm/ptrace.h is #included.
|
||||
#if defined(ARCH_CPU_RISCV64)
|
||||
#include <asm/ptrace.h>
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief The set of general purpose registers for an architecture family.
|
||||
@ -80,6 +85,8 @@ union ThreadContext {
|
||||
uint32_t cp0_status;
|
||||
uint32_t cp0_cause;
|
||||
uint32_t padding1_;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
// 32 bit RISC-V not supported
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
@ -133,12 +140,17 @@ union ThreadContext {
|
||||
uint64_t cp0_badvaddr;
|
||||
uint64_t cp0_status;
|
||||
uint64_t cp0_cause;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
// Reflects user_regs_struct in asm/ptrace.h.
|
||||
uint64_t pc;
|
||||
uint64_t regs[31];
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
} t64;
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM64)
|
||||
#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM64) || \
|
||||
defined(ARCH_CPU_RISCV64)
|
||||
using NativeThreadContext = user_regs_struct;
|
||||
#elif defined(ARCH_CPU_ARMEL)
|
||||
using NativeThreadContext = user_regs;
|
||||
@ -146,7 +158,7 @@ union ThreadContext {
|
||||
// No appropriate NativeThreadsContext type available for MIPS
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86_FAMILY || ARCH_CPU_ARM64
|
||||
#endif // ARCH_CPU_X86_FAMILY || ARCH_CPU_ARM64 || ARCH_CPU_RISCV64
|
||||
|
||||
#if !defined(ARCH_CPU_MIPS_FAMILY)
|
||||
#if defined(ARCH_CPU_32_BITS)
|
||||
@ -219,6 +231,8 @@ union FloatContext {
|
||||
} fpregs[32];
|
||||
uint32_t fpcsr;
|
||||
uint32_t fpu_id;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
// 32 bit RISC-V not supported
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
@ -253,6 +267,10 @@ union FloatContext {
|
||||
double fpregs[32];
|
||||
uint32_t fpcsr;
|
||||
uint32_t fpu_id;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
// Reflects __riscv_d_ext_state in asm/ptrace.h
|
||||
uint64_t fpregs[32];
|
||||
uint64_t fcsr;
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
@ -282,6 +300,8 @@ union FloatContext {
|
||||
static_assert(sizeof(f64) == sizeof(user_fpsimd_struct), "Size mismatch");
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
// No appropriate floating point context native type for available MIPS.
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
static_assert(sizeof(f64) == sizeof(__riscv_d_ext_state), "Size mismatch");
|
||||
#else
|
||||
#error Port.
|
||||
#endif // ARCH_CPU_X86
|
||||
|
@ -69,6 +69,7 @@ using NativeCPUContext = ucontext_t;
|
||||
//! macOS/Linux/Fuchsia | x86_64 | `%%rdi`
|
||||
//! Linux | ARM/ARM64 | `r0`/`x0`
|
||||
//! Linux | MIPS/MIPS64 | `$a0`
|
||||
//! Linux | RISCV64 | `a0`
|
||||
//!
|
||||
//! Additionally, the value `LR` on ARM/ARM64 will be the return address of
|
||||
//! this function.
|
||||
|
@ -36,6 +36,8 @@
|
||||
.type CAPTURECONTEXT_SYMBOL2, %function
|
||||
#elif defined(__mips__)
|
||||
.balign 4, 0x0
|
||||
#elif defined(__riscv)
|
||||
.balign 4, 0x0
|
||||
#endif
|
||||
|
||||
CAPTURECONTEXT_SYMBOL:
|
||||
@ -427,4 +429,85 @@ CAPTURECONTEXT_SYMBOL2:
|
||||
jr $ra
|
||||
|
||||
.set at
|
||||
|
||||
#elif defined(__riscv)
|
||||
|
||||
#define MCONTEXT_GREGS_OFFSET 176
|
||||
|
||||
// x1/ra is the return address. Store it as the pc.
|
||||
// The original x10/a0 can't be recovered.
|
||||
sd x1, (0 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x1, (1 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x2, (2 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x3, (3 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x4, (4 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x5, (5 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x6, (6 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x7, (7 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x8, (8 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x9, (9 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x10, (10 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x11, (11 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x12, (12 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x13, (13 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x14, (14 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x15, (15 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x16, (16 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x17, (17 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x18, (18 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x19, (19 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x20, (20 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x21, (21 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x22, (22 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x23, (23 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x24, (24 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x25, (25 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x26, (26 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x27, (27 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x28, (28 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x29, (29 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x30, (30 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd x31, (31 * 8 + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
|
||||
#define MCONTEXT_FPREGS_OFFSET MCONTEXT_GREGS_OFFSET + 32*8
|
||||
|
||||
// Use x31/t6 as scratch register.
|
||||
frcsr x31
|
||||
sw x31, (32 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
|
||||
fsd f0, (0 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f1, (1 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f2, (2 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f3, (3 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f4, (4 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f5, (5 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f6, (6 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f7, (7 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f8, (8 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f9, (9 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f10, (10 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f11, (11 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f12, (12 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f13, (13 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f14, (14 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f15, (15 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f16, (16 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f17, (17 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f18, (18 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f19, (19 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f20, (20 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f21, (21 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f22, (22 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f23, (23 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f24, (24 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f25, (25 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f26, (26 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f27, (27 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f28, (28 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f29, (29 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f30, (30 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
fsd f31, (31 * 8 + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
|
||||
ret
|
||||
|
||||
#endif // __i386__
|
||||
|
@ -35,6 +35,9 @@ void SanityCheckContext(const NativeCPUContext& context) {
|
||||
EXPECT_EQ(context.uc_mcontext.regs[0], FromPointerCast<uintptr_t>(&context));
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
EXPECT_EQ(context.uc_mcontext.gregs[4], FromPointerCast<uintptr_t>(&context));
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
EXPECT_EQ(context.uc_mcontext.__gregs[10],
|
||||
FromPointerCast<uintptr_t>(&context));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -49,6 +52,8 @@ uintptr_t ProgramCounterFromContext(const NativeCPUContext& context) {
|
||||
return context.uc_mcontext.pc;
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
return context.uc_mcontext.pc;
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
return context.uc_mcontext.__gregs[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -63,6 +68,8 @@ uintptr_t StackPointerFromContext(const NativeCPUContext& context) {
|
||||
return context.uc_mcontext.sp;
|
||||
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
||||
return context.uc_mcontext.gregs[29];
|
||||
#elif defined(ARCH_CPU_RISCV64)
|
||||
return context.uc_mcontext.__gregs[2];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -237,6 +237,8 @@ std::string UserAgent() {
|
||||
#elif defined(ARCH_CPU_BIG_ENDIAN)
|
||||
static constexpr char arch[] = "aarch64_be";
|
||||
#endif
|
||||
#elif defined (ARCH_CPU_RISCV64)
|
||||
static constexpr char arch[] = "riscv64";
|
||||
#else
|
||||
#error Port
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user