Browse Source

third_party: add new patchset

Credits to work published on felixonmars Github:
https://github.com/felixonmars/archriscv-packages/tree/master/chromium

Signed-off-by: Rebecca Chang Swee Fun <rebecca.chang@starfivetech.com>
Rebecca Chang Swee Fun 2 years ago
parent
commit
7df3ace90e

+ 13 - 0
third_party/0008-third-party-boringssl-src.patch

@@ -0,0 +1,13 @@
+diff --git a/include/openssl/base.h b/include/openssl/base.h
+index 983eadc5d..8a66adbbc 100644
+--- a/include/openssl/base.h
++++ b/include/openssl/base.h
+@@ -118,6 +118,8 @@ extern "C" {
+ #define OPENSSL_32_BIT
+ #elif defined(__myriad2__)
+ #define OPENSSL_32_BIT
++#elif defined(__riscv) && __riscv_xlen == 64
++#define OPENSSL_64_BIT
+ #else
+ // Note BoringSSL only supports standard 32-bit and 64-bit two's-complement,
+ // little-endian architectures. Functions will not produce the correct answer

+ 127 - 0
third_party/0009-third-party-breakpad-breakpad-header.patch

@@ -0,0 +1,127 @@
+diff --git a/src/google_breakpad/common/minidump_cpu_riscv64.h b/src/google_breakpad/common/minidump_cpu_riscv64.h
+new file mode 100644
+index 00000000..801aa821
+--- /dev/null
++++ b/src/google_breakpad/common/minidump_cpu_riscv64.h
+@@ -0,0 +1,121 @@
++/* Copyright 2013 Google Inc.
++ * 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.
++ *     * Neither the name of Google Inc. nor the names of its
++ * contributors may be used to endorse or promote products derived from
++ * this software without specific prior written permission.
++ *
++ * 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. */
++
++/* minidump_format.h: A cross-platform reimplementation of minidump-related
++ * portions of DbgHelp.h from the Windows Platform SDK.
++ *
++ * (This is C99 source, please don't corrupt it with C.)
++ *
++ * This file contains the necessary definitions to read minidump files
++ * produced on ARM.  These files may be read on any platform provided
++ * that the alignments of these structures on the processing system are
++ * identical to the alignments of these structures on the producing system.
++ * For this reason, precise-sized types are used.  The structures defined
++ * by this file have been laid out to minimize alignment problems by
++ * ensuring that all members are aligned on their natural boundaries.
++ * In some cases, tail-padding may be significant when different ABIs specify
++ * different tail-padding behaviors.  To avoid problems when reading or
++ * writing affected structures, MD_*_SIZE macros are provided where needed,
++ * containing the useful size of the structures without padding.
++ *
++ * Structures that are defined by Microsoft to contain a zero-length array
++ * are instead defined here to contain an array with one element, as
++ * zero-length arrays are forbidden by standard C and C.  In these cases,
++ * *_minsize constants are provided to be used in place of sizeof.  For a
++ * cleaner interface to these sizes when using C, see minidump_size.h.
++ *
++ * These structures are also sufficient to populate minidump files.
++ *
++ * Because precise data type sizes are crucial for this implementation to
++ * function properly and portably, a set of primitive types with known sizes
++ * are used as the basis of each structure defined by this file.
++ *
++ * Author: Colin Blundell
++ */
++
++/*
++ * RISCV64 support
++ */
++
++#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV64_H__
++#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV64_H__
++
++#include "google_breakpad/common/breakpad_types.h"
++
++#define MD_FLOATINGSAVEAREA_RISCV64_FPR_COUNT 32
++#define MD_CONTEXT_RISCV64_GPR_COUNT 32
++
++typedef struct {
++  /* 32 64-bit floating point registers, f0 .. f31. */
++  uint64_t regs[MD_FLOATINGSAVEAREA_RISCV64_FPR_COUNT];
++
++  uint32_t fcsr;       /* FPU control and status register */
++} MDFloatingSaveAreaRISCV64;
++
++/* For (MDRawContextRISCV64).context_flags.  These values indicate the type of
++ * context stored in the structure. */
++#define MD_CONTEXT_RISCV64 0x00400000
++#define MD_CONTEXT_RISCV64_CONTROL (MD_CONTEXT_RISCV64 | 0x00000001)
++#define MD_CONTEXT_RISCV64_INTEGER (MD_CONTEXT_RISCV64 | 0x00000002)
++#define MD_CONTEXT_RISCV64_FLOATING_POINT (MD_CONTEXT_RISCV64 | 0x00000004)
++#define MD_CONTEXT_RISCV64_DEBUG (MD_CONTEXT_RISCV64 | 0x00000008)
++#define MD_CONTEXT_RISCV64_FULL (MD_CONTEXT_RISCV64_CONTROL | \
++                               MD_CONTEXT_RISCV64_INTEGER | \
++                               MD_CONTEXT_RISCV64_FLOATING_POINT)
++#define MD_CONTEXT_RISCV64_ALL (MD_CONTEXT_RISCV64_FULL | MD_CONTEXT_RISCV64_DEBUG)
++
++typedef struct {
++  /* Determines which fields of this struct are populated */
++  uint32_t context_flags;
++
++  /* 32 64-bit integer registers, x1 .. x31  the PC
++   * Note the following fixed uses:
++   *   x8 is the frame pointer
++   *   x1 is the link register
++   *   x2 is the stack pointer
++   *   The PC is effectively x0.
++   */
++  uint64_t iregs[MD_CONTEXT_RISCV64_GPR_COUNT];
++
++  /* The next field is included with MD_CONTEXT64_ARM_FLOATING_POINT */
++  MDFloatingSaveAreaRISCV64 float_save;
++
++} MDRawContextRISCV64;
++
++/* Indices into iregs for registers with a dedicated or conventional
++ * purpose.
++ */
++enum MDRISCV64RegisterNumbers {
++  MD_CONTEXT_RISCV64_REG_FP     = 8,
++  MD_CONTEXT_RISCV64_REG_RA     = 1,
++  MD_CONTEXT_RISCV64_REG_SP     = 2,
++  MD_CONTEXT_RISCV64_REG_PC     = 0
++};
++
++#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV64_H__ */

+ 440 - 0
third_party/0010-third-party-breakpad-breakpad.patch

@@ -0,0 +1,440 @@
+diff --git a/src/client/linux/dump_writer_common/raw_context_cpu.h b/src/client/linux/dump_writer_common/raw_context_cpu.h
+index 07d9171a..24b76143 100644
+--- a/src/client/linux/dump_writer_common/raw_context_cpu.h
++++ b/src/client/linux/dump_writer_common/raw_context_cpu.h
+@@ -44,6 +44,8 @@ typedef MDRawContextARM RawContextCPU;
+ typedef MDRawContextARM64_Old RawContextCPU;
+ #elif defined(__mips__)
+ typedef MDRawContextMIPS RawContextCPU;
++#elif defined(__riscv)
++typedef MDRawContextRISCV64 RawContextCPU;
+ #else
+ #error "This code has not been ported to your platform yet."
+ #endif
+diff --git a/src/client/linux/dump_writer_common/thread_info.cc b/src/client/linux/dump_writer_common/thread_info.cc
+index aae1dc13..39013591 100644
+--- a/src/client/linux/dump_writer_common/thread_info.cc
++++ b/src/client/linux/dump_writer_common/thread_info.cc
+@@ -270,7 +270,22 @@ 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[REG_PC];
++}
++
++void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
++  out->context_flags = MD_CONTEXT_RISCV64_FULL;
++  my_memcpy (out->iregs, mcontext.__gregs, MD_CONTEXT_RISCV64_GPR_COUNT * 8);
++
++  out->float_save.fcsr = mcontext.__fpregs.__d.__fcsr;
++  my_memcpy(&out->float_save.regs, &mcontext.__fpregs.__d.__f,
++      MD_FLOATINGSAVEAREA_RISCV64_FPR_COUNT * 8);
++}
++
++#endif  // __riscv
+ 
+ void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
+   assert(gp_regs || size);
+@@ -279,6 +294,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;
+@@ -294,6 +314,11 @@ void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) {
+     *fp_regs = &mcontext.fpregs;
+   if (size)
+     *size = sizeof(mcontext.fpregs);
++#elif defined(__riscv)
++  if (fp_regs)
++    *fp_regs = &mcontext.__fpregs;
++  if (size)
++    *size = sizeof(mcontext.__fpregs);
+ #else
+   if (fp_regs)
+     *fp_regs = &fpregs;
+diff --git a/src/client/linux/dump_writer_common/thread_info.h b/src/client/linux/dump_writer_common/thread_info.h
+index fb216fa6..65c231b4 100644
+--- a/src/client/linux/dump_writer_common/thread_info.h
++++ b/src/client/linux/dump_writer_common/thread_info.h
+@@ -68,7 +68,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
+diff --git a/src/client/linux/dump_writer_common/ucontext_reader.cc b/src/client/linux/dump_writer_common/ucontext_reader.cc
+index 6eec1be2..c485e52c 100644
+--- a/src/client/linux/dump_writer_common/ucontext_reader.cc
++++ b/src/client/linux/dump_writer_common/ucontext_reader.cc
+@@ -254,6 +254,26 @@ 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[REG_SP];
++}
++
++uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
++  return uc->uc_mcontext.__gregs[REG_PC];
++}
++
++void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
++  out->context_flags = MD_CONTEXT_RISCV64_FULL;
++  for (int i = 0; i < MD_CONTEXT_RISCV64_GPR_COUNT; ++i)
++    out->iregs[i] = uc->uc_mcontext.__gregs[i];
++
++  out->float_save.fcsr = uc->uc_mcontext.__fpregs.__d.__fcsr;
++  for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV64_FPR_COUNT; ++i)
++    out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__d.__f[i];
++}
+ #endif
+ 
+ }  // namespace google_breakpad
+diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc
+index 499be0a9..7e24a027 100644
+--- a/src/client/linux/handler/exception_handler.cc
++++ b/src/client/linux/handler/exception_handler.cc
+@@ -461,7 +461,7 @@ bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) {
+     memcpy(&g_crash_context_.float_state, fp_ptr,
+            sizeof(g_crash_context_.float_state));
+   }
+-#elif !defined(__ARM_EABI__) && !defined(__mips__)
++#elif !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
+   // 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.
+@@ -701,7 +701,7 @@ bool ExceptionHandler::WriteMinidump() {
+   }
+ #endif
+ 
+-#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__)
++#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) && !defined(__riscv)
+   // FPU state is not part of ARM EABI ucontext_t.
+   memcpy(&context.float_state, context.context.uc_mcontext.fpregs,
+          sizeof(context.float_state));
+@@ -726,6 +726,9 @@ 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."
+ #endif
+diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h
+index f80843ea..6d2ab077 100644
+--- a/src/client/linux/handler/exception_handler.h
++++ b/src/client/linux/handler/exception_handler.h
+@@ -192,7 +192,7 @@ class ExceptionHandler {
+     siginfo_t siginfo;
+     pid_t tid;  // the crashing thread.
+     ucontext_t context;
+-#if !defined(__ARM_EABI__) && !defined(__mips__)
++#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
+     // #ifdef this out because FP state is not part of user ABI for Linux ARM.
+     // In case of MIPS Linux FP state is already part of ucontext_t so
+     // 'float_state' is not required.
+diff --git a/src/client/linux/microdump_writer/microdump_writer.cc b/src/client/linux/microdump_writer/microdump_writer.cc
+index 22edb1b8..84fb37b9 100644
+--- a/src/client/linux/microdump_writer/microdump_writer.cc
++++ b/src/client/linux/microdump_writer/microdump_writer.cc
+@@ -138,7 +138,7 @@ class MicrodumpWriter {
+                   const MicrodumpExtraInfo& microdump_extra_info,
+                   LinuxDumper* dumper)
+       : ucontext_(context ? &context->context : NULL),
+-#if !defined(__ARM_EABI__) && !defined(__mips__)
++#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
+         float_state_(context ? &context->float_state : NULL),
+ #endif
+         dumper_(dumper),
+@@ -337,6 +337,12 @@ class MicrodumpWriter {
+ # else
+ #  error "This mips ABI is currently not supported (n32)"
+ #endif
++#elif defined(__riscv)
++# if __riscv_xlen == 64
++    const char kArch[] = "riscv64";
++#else
++#  error "This RISC-V ABI is currently not supported"
++#endif
+ #else
+ #error "This code has not been ported to your platform yet"
+ #endif
+@@ -409,7 +415,7 @@ class MicrodumpWriter {
+   void DumpCPUState() {
+     RawContextCPU cpu;
+     my_memset(&cpu, 0, sizeof(RawContextCPU));
+-#if !defined(__ARM_EABI__) && !defined(__mips__)
++#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
+     UContextReader::FillCPUContext(&cpu, ucontext_, float_state_);
+ #else
+     UContextReader::FillCPUContext(&cpu, ucontext_);
+@@ -605,7 +611,7 @@ class MicrodumpWriter {
+   void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); }
+ 
+   const ucontext_t* const ucontext_;
+-#if !defined(__ARM_EABI__) && !defined(__mips__)
++#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
+   const google_breakpad::fpstate_t* const float_state_;
+ #endif
+   LinuxDumper* dumper_;
+diff --git a/src/client/linux/minidump_writer/linux_core_dumper.cc b/src/client/linux/minidump_writer/linux_core_dumper.cc
+index 92e3a844..1789c810 100644
+--- a/src/client/linux/minidump_writer/linux_core_dumper.cc
++++ b/src/client/linux/minidump_writer/linux_core_dumper.cc
+@@ -112,6 +112,9 @@ 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_RISCV64_REG_SP]);
+ #else
+ #error "This code hasn't been ported to your platform yet."
+ #endif
+@@ -218,6 +221,8 @@ bool LinuxCoreDumper::EnumerateThreads() {
+         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];
++#elif defined(__riscv)
++        memcpy(info.mcontext.__gregs, status->pr_reg, sizeof(info.mcontext.__gregs));
+ #else  // __mips__
+         memcpy(&info.regs, status->pr_reg, sizeof(info.regs));
+ #endif  // __mips__
+diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h
+index 7bee160f..df04e2c0 100644
+--- a/src/client/linux/minidump_writer/linux_dumper.h
++++ b/src/client/linux/minidump_writer/linux_dumper.h
+@@ -63,7 +63,8 @@ namespace google_breakpad {
+  (defined(__mips__) && _MIPS_SIM == _ABIO32)
+ 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
+ 
+diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
+index e3ddb81a..0295fa3b 100644
+--- a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
++++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
+@@ -298,6 +298,9 @@ 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_RISCV64_REG_SP]);
+ #else
+ #error "This code hasn't been ported to your platform yet."
+ #endif
+diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc
+index 72a92166..bc54a4bb 100644
+--- a/src/client/linux/minidump_writer/minidump_writer.cc
++++ b/src/client/linux/minidump_writer/minidump_writer.cc
+@@ -136,7 +136,7 @@ class MinidumpWriter {
+       : fd_(minidump_fd),
+         path_(minidump_path),
+         ucontext_(context ? &context->context : NULL),
+-#if !defined(__ARM_EABI__) && !defined(__mips__)
++#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
+         float_state_(context ? &context->float_state : NULL),
+ #endif
+         dumper_(dumper),
+@@ -468,7 +468,7 @@ class MinidumpWriter {
+         if (!cpu.Allocate())
+           return false;
+         my_memset(cpu.get(), 0, sizeof(RawContextCPU));
+-#if !defined(__ARM_EABI__) && !defined(__mips__)
++#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
+         UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_);
+ #else
+         UContextReader::FillCPUContext(cpu.get(), ucontext_);
+@@ -897,7 +897,7 @@ class MinidumpWriter {
+     dirent->location.rva = 0;
+   }
+ 
+-#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
++#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || defined(__riscv)
+   bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
+     char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0};
+     static const char vendor_id_name[] = "vendor_id";
+@@ -925,6 +925,12 @@ class MinidumpWriter {
+ # else
+ #  error "This mips ABI is currently not supported (n32)"
+ #endif
++#elif defined(__riscv)
++# if __riscv_xlen == 64
++        MD_CPU_ARCHITECTURE_RISCV64;
++# else
++# error "This RISC-V ABI us currently not supported"
++# endif
+ #elif defined(__i386__)
+         MD_CPU_ARCHITECTURE_X86;
+ #else
+@@ -1333,7 +1339,7 @@ class MinidumpWriter {
+   const char* path_;  // Path to the file where the minidum should be written.
+ 
+   const ucontext_t* const ucontext_;  // also from the signal handler
+-#if !defined(__ARM_EABI__) && !defined(__mips__)
++#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
+   const google_breakpad::fpstate_t* const float_state_;  // ditto
+ #endif
+   LinuxDumper* dumper_;
+diff --git a/src/client/linux/minidump_writer/minidump_writer.h b/src/client/linux/minidump_writer/minidump_writer.h
+index e3b0b16d..0d18c328 100644
+--- a/src/client/linux/minidump_writer/minidump_writer.h
++++ b/src/client/linux/minidump_writer/minidump_writer.h
+@@ -48,7 +48,7 @@ class ExceptionHandler;
+ 
+ #if defined(__aarch64__)
+ typedef struct fpsimd_context fpstate_t;
+-#elif !defined(__ARM_EABI__) && !defined(__mips__)
++#elif !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
+ typedef std::remove_pointer<fpregset_t>::type fpstate_t;
+ #endif
+ 
+diff --git a/src/common/linux/breakpad_getcontext.S b/src/common/linux/breakpad_getcontext.S
+index 2ebcf319..b3c2873b 100644
+--- a/src/common/linux/breakpad_getcontext.S
++++ b/src/common/linux/breakpad_getcontext.S
+@@ -526,6 +526,67 @@ breakpad_getcontext:
+   ret
+   .cfi_endproc
+   .size breakpad_getcontext, . - breakpad_getcontext
++#elif defined(__riscv) && __riscv_xlen == 64
++
++#define __NR_rt_sigprocmask 135
++#define _NSIG8 64 / 8
++#define SIG_BLOCK 0
++
++  .text
++  .global breakpad_getcontext
++  .hidden breakpad_getcontext
++  .type breakpad_getcontext, @function
++  .align 2
++breakpad_getcontext:
++  sd ra, MCONTEXT_GREGS_OFFSET + 0*8(a0)
++  sd ra, MCONTEXT_GREGS_OFFSET + 1*8(a0)
++  sd sp, MCONTEXT_GREGS_OFFSET + 2*8(a0)
++  sd s0, MCONTEXT_GREGS_OFFSET + 8*8(a0)
++  sd s1, MCONTEXT_GREGS_OFFSET + 9*8(a0)
++  sd x0, MCONTEXT_GREGS_OFFSET + 10*8(a0)	/* return 0 by overwriting a0.  */
++  sd s2, MCONTEXT_GREGS_OFFSET + 18*8(a0)
++  sd s3, MCONTEXT_GREGS_OFFSET + 19*8(a0)
++  sd s4, MCONTEXT_GREGS_OFFSET + 20*8(a0)
++  sd s5, MCONTEXT_GREGS_OFFSET + 21*8(a0)
++  sd s6, MCONTEXT_GREGS_OFFSET + 22*8(a0)
++  sd s7, MCONTEXT_GREGS_OFFSET + 23*8(a0)
++  sd s8, MCONTEXT_GREGS_OFFSET + 24*8(a0)
++  sd s9, MCONTEXT_GREGS_OFFSET + 25*8(a0)
++  sd s10, MCONTEXT_GREGS_OFFSET + 26*8(a0)
++  sd s11, MCONTEXT_GREGS_OFFSET + 27*8(a0)
++
++#ifndef __riscv_float_abi_soft
++  frsr	a1
++
++  fsd fs0, MCONTEXT_FPREGS_OFFSET + 8*8(a0)
++  fsd fs1, MCONTEXT_FPREGS_OFFSET + 9*8(a0)
++  fsd fs2, MCONTEXT_FPREGS_OFFSET + 18*8(a0)
++  fsd fs3, MCONTEXT_FPREGS_OFFSET + 19*8(a0)
++  fsd fs4, MCONTEXT_FPREGS_OFFSET + 20*8(a0)
++  fsd fs5, MCONTEXT_FPREGS_OFFSET + 21*8(a0)
++  fsd fs6, MCONTEXT_FPREGS_OFFSET + 22*8(a0)
++  fsd fs7, MCONTEXT_FPREGS_OFFSET + 23*8(a0)
++  fsd fs8, MCONTEXT_FPREGS_OFFSET + 24*8(a0)
++  fsd fs9, MCONTEXT_FPREGS_OFFSET + 25*8(a0)
++  fsd fs10, MCONTEXT_FPREGS_OFFSET + 26*8(a0)
++  fsd fs11, MCONTEXT_FPREGS_OFFSET + 27*8(a0)
++
++  sw	a1, MCONTEXT_FSR_OFFSET(a0)
++#endif /* __riscv_float_abi_soft */
++
++/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG / 8) */
++  li	a3, _NSIG8
++  add	a2, a0, UCONTEXT_SIGMASK_OFFSET
++  mv	a1, zero
++  li	a0, SIG_BLOCK
++
++  li	a7, __NR_rt_sigprocmask
++  scall
++
++  /* Always return 0 for success, even if sigprocmask failed. */
++  mv	a0, zero
++  ret
++  .size breakpad_getcontext, . - breakpad_getcontext
+ 
+ #else
+ #error "This file has not been ported for your CPU!"
+diff --git a/src/common/linux/memory_mapped_file.cc b/src/common/linux/memory_mapped_file.cc
+index 99362945..f70549fd 100644
+--- a/src/common/linux/memory_mapped_file.cc
++++ b/src/common/linux/memory_mapped_file.cc
+@@ -65,7 +65,8 @@ bool MemoryMappedFile::Map(const char* path, size_t offset) {
+   }
+ 
+ #if defined(__x86_64__) || defined(__aarch64__) || \
+-   (defined(__mips__) && _MIPS_SIM == _ABI64)
++   (defined(__mips__) && _MIPS_SIM == _ABI64) ||   \
++   (defined(__riscv) && __riscv_xlen == 64)
+ 
+   struct kernel_stat st;
+   if (sys_fstat(fd, &st) == -1 || st.st_size < 0) {
+diff --git a/src/common/linux/ucontext_constants.h b/src/common/linux/ucontext_constants.h
+index c390508a..0a970e3b 100644
+--- a/src/common/linux/ucontext_constants.h
++++ b/src/common/linux/ucontext_constants.h
+@@ -146,6 +146,14 @@
+ #endif
+ #define FPREGS_OFFSET_MXCSR  24
+ 
++#elif defined(__riscv)
++
++#define UCONTEXT_SIGMASK_OFFSET   40
++
++#define MCONTEXT_GREGS_OFFSET     176
++#define MCONTEXT_FPREGS_OFFSET    432
++#define MCONTEXT_FSR_OFFSET       (MCONTEXT_FPREGS_OFFSET + 32*8)
++
+ #else
+ #error "This header has not been ported for your CPU"
+ #endif
+diff --git a/src/google_breakpad/common/minidump_format.h b/src/google_breakpad/common/minidump_format.h
+index 7b36d112..1013a891 100644
+--- a/src/google_breakpad/common/minidump_format.h
++++ b/src/google_breakpad/common/minidump_format.h
+@@ -118,6 +118,7 @@ typedef struct {
+ #include "minidump_cpu_mips.h"
+ #include "minidump_cpu_ppc.h"
+ #include "minidump_cpu_ppc64.h"
++#include "minidump_cpu_riscv64.h"
+ #include "minidump_cpu_sparc.h"
+ #include "minidump_cpu_x86.h"
+ 
+@@ -660,6 +661,7 @@ typedef enum {
+   MD_CPU_ARCHITECTURE_PPC64     = 0x8002, /* Breakpad-defined value for PPC64 */
+   MD_CPU_ARCHITECTURE_ARM64_OLD = 0x8003, /* Breakpad-defined value for ARM64 */
+   MD_CPU_ARCHITECTURE_MIPS64    = 0x8004, /* Breakpad-defined value for MIPS64 */
++  MD_CPU_ARCHITECTURE_RISCV64   = 0x8005, /* Breakpad-defined value for RISCV64 */
+   MD_CPU_ARCHITECTURE_UNKNOWN   = 0xffff  /* PROCESSOR_ARCHITECTURE_UNKNOWN */
+ } MDCPUArchitecture;
+ 

+ 773 - 0
third_party/0011-third-party-crashpad-crashpad.patch

@@ -0,0 +1,773 @@
+diff --git a/third_party/crashpad/crashpad/minidump/minidump_context.h b/third_party/crashpad/crashpad/minidump/minidump_context.h
+index 3a3e603cb0d2d..cf074d2b8236b 100644
+--- a/third_party/crashpad/crashpad/minidump/minidump_context.h
++++ b/third_party/crashpad/crashpad/minidump/minidump_context.h
+@@ -592,6 +592,41 @@ struct MinidumpContextMIPS64 {
+   uint64_t fir;
+ };
+ 
++//! \brief 64bit RISC-V-specifc flags for MinidumpContextRISCV64::context_flags.
++//! Based on minidump_cpu_riscv64.h from breakpad
++enum MinidumpContextRISCV64Flags : uint32_t {
++  //! \brief Identifies the context structure as RISCV64.
++  kMinidumpContextRISCV64 = 0x00080000,
++
++  //! \brief Indicates the validity of integer registers.
++  //!
++  //! Registers `x1`-`x31` and pc are valid.
++  kMinidumpContextRISCV64Integer = kMinidumpContextRISCV64 | 0x00000002,
++
++  //! \brief Indicates the validity of floating point registers.
++  //!
++  //! Floating point registers `f0`-`f31`, and `fcsr` are valid
++  kMinidumpContextRISCV64FloatingPoint = kMinidumpContextRISCV64 | 0x00000004,
++
++  //! \brief Indicates the validity of all registers.
++  kMinidumpContextRISCV64All = kMinidumpContextRISCV64Integer |
++                              kMinidumpContextRISCV64FloatingPoint,
++};
++
++//! \brief A 64bit RISCV CPU context (register state) carried in a minidump file.
++struct MinidumpContextRISCV64 {
++  uint64_t context_flags;
++
++  //! \brief General purpose registers.
++  uint64_t regs[32];
++
++  //! \brief FPU registers.
++  uint64_t fpregs[32];
++
++  //! \brief FPU status register.
++  uint64_t fcsr;
++};
++
+ }  // namespace crashpad
+ 
+ #endif  // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_H_
+diff --git a/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
+index 2f2d90ba47071..ad26739432f51 100644
+--- a/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
++++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
+@@ -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;
+@@ -454,4 +461,41 @@ size_t MinidumpContextMIPS64Writer::ContextSize() const {
+   return sizeof(context_);
+ }
+ 
++MinidumpContextRISCV64Writer::MinidumpContextRISCV64Writer()
++    : MinidumpContextWriter(), context_() {
++  context_.context_flags = kMinidumpContextRISCV64;
++}
++
++MinidumpContextRISCV64Writer::~MinidumpContextRISCV64Writer() = default;
++
++void MinidumpContextRISCV64Writer::InitializeFromSnapshot(
++    const CPUContextRISCV64* context_snapshot) {
++  DCHECK_EQ(state(), kStateMutable);
++  DCHECK_EQ(context_.context_flags, kMinidumpContextRISCV64);
++
++  context_.context_flags = kMinidumpContextRISCV64All;
++
++  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
+diff --git a/third_party/crashpad/crashpad/minidump/minidump_context_writer.h b/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
+index 80b312b23c2a4..278830085c162 100644
+--- a/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
++++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
+@@ -330,6 +330,47 @@ 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() override;
++
++  MinidumpContextRISCV64Writer(const MinidumpContextRISCV64Writer&) = delete;
++  void operator=(const MinidumpContextRISCV64Writer&) = delete;
++
++  //! \brief Initializes the MinidumpContextRISCV 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_
+diff --git a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
+index 78847c11970e5..b2a1486dfbbf0 100644
+--- a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
++++ b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
+@@ -135,6 +135,10 @@ std::string MinidumpMiscInfoDebugBuildString() {
+   static constexpr char kCPU[] = "mips";
+ #elif defined(ARCH_CPU_MIPS64EL)
+   static constexpr char kCPU[] = "mips64";
++#elif defined(ARCH_CPU_RISCV)
++  static constexpr char kCPU[] = "riscv";
++#elif defined(ARCH_CPU_RISCV64)
++  static constexpr char kCPU[] = "riscv64";
+ #else
+ #error define kCPU for this CPU
+ #endif
+diff --git a/third_party/crashpad/crashpad/snapshot/capture_memory.cc b/third_party/crashpad/crashpad/snapshot/capture_memory.cc
+index 06d92581330bf..a8b52d11b9b53 100644
+--- a/third_party/crashpad/crashpad/snapshot/capture_memory.cc
++++ b/third_party/crashpad/crashpad/snapshot/capture_memory.cc
+@@ -112,6 +112,16 @@ 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_RISCV_FAMILY)
++  if (context.architecture == kCPUArchitectureRISCV) {
++    for (size_t i = 0; i < base::size(context.riscv->regs); ++i) {
++      MaybeCaptureMemoryAround(delegate, context.riscv->regs[i]);
++    }
++  } else {
++    for (size_t i = 0; i < base::size(context.riscv64->regs); ++i) {
++      MaybeCaptureMemoryAround(delegate, context.riscv64->regs[i]);
++    }
++  }
+ #else
+ #error Port.
+ #endif
+diff --git a/third_party/crashpad/crashpad/snapshot/cpu_architecture.h b/third_party/crashpad/crashpad/snapshot/cpu_architecture.h
+index 811a7209587d2..5b09abdb96761 100644
+--- a/third_party/crashpad/crashpad/snapshot/cpu_architecture.h
++++ b/third_party/crashpad/crashpad/snapshot/cpu_architecture.h
+@@ -43,7 +43,13 @@ enum CPUArchitecture {
+   kCPUArchitectureMIPSEL,
+ 
+   //! \brief 64-bit MIPSEL.
+-  kCPUArchitectureMIPS64EL
++  kCPUArchitectureMIPS64EL,
++
++  //! \brief 32-bit RISCV.
++  kCPUArchitectureRISCV,
++
++  //! \brief 64-bit RISCV.
++  kCPUArchitectureRISCV64
+ };
+ 
+ }  // namespace crashpad
+diff --git a/third_party/crashpad/crashpad/snapshot/cpu_context.cc b/third_party/crashpad/crashpad/snapshot/cpu_context.cc
+index 2e29f70398c9f..e2f8097e2cae1 100644
+--- a/third_party/crashpad/crashpad/snapshot/cpu_context.cc
++++ b/third_party/crashpad/crashpad/snapshot/cpu_context.cc
+@@ -197,10 +197,12 @@ bool CPUContext::Is64Bit() const {
+     case kCPUArchitectureX86_64:
+     case kCPUArchitectureARM64:
+     case kCPUArchitectureMIPS64EL:
++    case kCPUArchitectureRISCV64:
+       return true;
+     case kCPUArchitectureX86:
+     case kCPUArchitectureARM:
+     case kCPUArchitectureMIPSEL:
++    case kCPUArchitectureRISCV:
+       return false;
+     default:
+       NOTREACHED();
+diff --git a/third_party/crashpad/crashpad/snapshot/cpu_context.h b/third_party/crashpad/crashpad/snapshot/cpu_context.h
+index fb23c4679f0af..e120a980448d6 100644
+--- a/third_party/crashpad/crashpad/snapshot/cpu_context.h
++++ b/third_party/crashpad/crashpad/snapshot/cpu_context.h
+@@ -352,6 +352,20 @@ struct CPUContextMIPS64 {
+   uint64_t fir;
+ };
+ 
++//! \brief A context structure carrying RISC CPU state.
++struct CPUContextRISCV {
++  uint32_t regs[32];
++  uint64_t fpregs[32];
++  uint32_t fcsr;
++};
++
++//! \brief A context structure carrying RISC64 CPU state.
++struct CPUContextRISCV64 {
++  uint64_t regs[32];
++  uint64_t fpregs[32];
++  uint32_t fcsr;
++};
++
+ //! \brief A context structure capable of carrying the context of any supported
+ //!     CPU architecture.
+ struct CPUContext {
+@@ -382,6 +396,8 @@ struct CPUContext {
+     CPUContextARM64* arm64;
+     CPUContextMIPS* mipsel;
+     CPUContextMIPS64* mips64;
++    CPUContextRISCV* riscv;
++    CPUContextRISCV64* riscv64;
+   };
+ };
+ 
+diff --git a/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc
+index 8464a5a27b2dc..ec41216daa902 100644
+--- a/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc
++++ b/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc
+@@ -266,6 +266,30 @@ void InitializeCPUContextARM64_OnlyFPSIMD(
+   context->fpcr = float_context.fpcr;
+ }
+ 
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++
++template <typename Traits>
++void InitializeCPUContextRISCV(
++    const typename Traits::SignalThreadContext& thread_context,
++    const typename Traits::SignalFloatContext& float_context,
++    typename Traits::CPUContext* context) {
++  static_assert(sizeof(context->regs) == sizeof(thread_context),
++                "registers size mismatch");
++  static_assert(sizeof(context->fpregs) == sizeof(float_context.f),
++                "fp registers size mismatch");
++  memcpy(&context->regs, &thread_context, sizeof(context->regs));
++  memcpy(&context->fpregs, &float_context, sizeof(context->fpregs));
++  context->fcsr = float_context.fcsr;
++}
++template void InitializeCPUContextRISCV<ContextTraits32>(
++    const ContextTraits32::SignalThreadContext& thread_context,
++    const ContextTraits32::SignalFloatContext& float_context,
++    ContextTraits32::CPUContext* context);
++template void InitializeCPUContextRISCV<ContextTraits64>(
++    const ContextTraits64::SignalThreadContext& thread_context,
++    const ContextTraits64::SignalFloatContext& float_context,
++    ContextTraits64::CPUContext* context);
++
+ #endif  // ARCH_CPU_X86_FAMILY
+ 
+ }  // namespace internal
+diff --git a/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h b/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h
+index 9f46a48977e12..1add07f81af88 100644
+--- a/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h
++++ b/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h
+@@ -174,6 +174,22 @@ void InitializeCPUContextMIPS(
+ 
+ #endif  // ARCH_CPU_MIPS_FAMILY || DOXYGEN
+ 
++#if defined(ARCH_CPU_RISCV_FAMILY) || DOXYGEN
++
++//! \brief Initializes a CPUContextRISCV 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 CPUContextRISCV structure to initialize.
++template <typename Traits>
++void InitializeCPUContextRISCV(
++    const typename Traits::SignalThreadContext& thread_context,
++    const typename Traits::SignalFloatContext& float_context,
++    typename Traits::CPUContext* context);
++
++#endif  // ARCH_CPU_RISCV_FAMILY || DOXYGEN
++
+ }  // namespace internal
+ }  // namespace crashpad
+ 
+diff --git a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc
+index efc9e5694ea8b..3d57d96756208 100644
+--- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc
++++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc
+@@ -325,6 +325,61 @@ bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
+       reader, context_address, context_.mips64);
+ }
+ 
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++
++template <typename Traits>
++static bool ReadContext(ProcessReaderLinux* reader,
++                        LinuxVMAddress context_address,
++                        typename Traits::CPUContext* dest_context) {
++  const ProcessMemory* memory = reader->Memory();
++
++  LinuxVMAddress gregs_address = context_address +
++                                 offsetof(UContext<Traits>, mcontext) +
++                                 offsetof(typename Traits::MContext, gregs);
++
++  typename Traits::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<Traits>, mcontext) +
++                                  offsetof(typename Traits::MContext, fpregs);
++
++  typename Traits::SignalFloatContext fp_context;
++  if (!memory->Read(fpregs_address, sizeof(fp_context), &fp_context)) {
++    LOG(ERROR) << "Couldn't read fpregs";
++    return false;
++  }
++
++  InitializeCPUContextRISCV<Traits>(thread_context, fp_context, dest_context);
++
++  return true;
++}
++
++template <>
++bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
++    ProcessReaderLinux* reader,
++    LinuxVMAddress context_address) {
++  context_.architecture = kCPUArchitectureRISCV;
++  context_.riscv = &context_union_.riscv;
++
++  return internal::ReadContext<ContextTraits32>(
++      reader, context_address, context_.riscv);
++}
++
++template <>
++bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
++    ProcessReaderLinux* reader,
++    LinuxVMAddress context_address) {
++  context_.architecture = kCPUArchitectureRISCV64;
++  context_.riscv64 = &context_union_.riscv64;
++
++  return internal::ReadContext<ContextTraits64>(
++      reader, context_address, context_.riscv64);
++}
++
+ #endif  // ARCH_CPU_X86_FAMILY
+ 
+ bool ExceptionSnapshotLinux::Initialize(
+diff --git a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h
+index 05f6004e11d1e..0520af4ce9019 100644
+--- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h
++++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h
+@@ -89,6 +89,9 @@ class ExceptionSnapshotLinux final : public ExceptionSnapshot {
+ #elif defined(ARCH_CPU_MIPS_FAMILY)
+     CPUContextMIPS mipsel;
+     CPUContextMIPS64 mips64;
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++    CPUContextRISCV riscv;
++    CPUContextRISCV64 riscv64;
+ #endif
+   } context_union_;
+   CPUContext context_;
+diff --git a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
+index 5711f343a46c4..abbb1662c3e0a 100644
+--- a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
++++ b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
+@@ -108,6 +108,9 @@ 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_RISCV_FAMILY)
++  stack_pointer = reader->Is64Bit() ? thread_info.thread_context.t64.sp
++                                    : thread_info.thread_context.t32.sp;
+ #else
+ #error Port.
+ #endif
+diff --git a/third_party/crashpad/crashpad/snapshot/linux/signal_context.h b/third_party/crashpad/crashpad/snapshot/linux/signal_context.h
+index c004f8f6dfab6..6aa9ee38f5b04 100644
+--- a/third_party/crashpad/crashpad/snapshot/linux/signal_context.h
++++ b/third_party/crashpad/crashpad/snapshot/linux/signal_context.h
+@@ -422,6 +422,67 @@ static_assert(offsetof(UContext<ContextTraits64>, mcontext.fpregs) ==
+               "context offset mismatch");
+ #endif
+ 
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++
++struct MContext32 {
++  uint32_t gregs[32];
++  uint64_t fpregs[32];
++  unsigned int fcsr;
++};
++
++struct MContext64 {
++  uint64_t gregs[32];
++  uint64_t fpregs[32];
++  unsigned int fcsr;
++};
++
++struct ContextTraits32 : public Traits32 {
++  using MContext = MContext32;
++  using SignalThreadContext = ThreadContext::t32_t;
++  using SignalFloatContext = FloatContext::f32_t;
++  using CPUContext = CPUContextRISCV;
++};
++
++struct ContextTraits64 : public Traits64 {
++  using MContext = MContext64;
++  using SignalThreadContext = ThreadContext::t64_t;
++  using SignalFloatContext = FloatContext::f64_t;
++  using CPUContext = CPUContextRISCV64;
++};
++
++template <typename Traits>
++struct UContext {
++  typename Traits::ULong flags;
++  typename Traits::Address link;
++  SignalStack<Traits> stack;
++  Sigset<Traits> sigmask;
++  char padding[128 - sizeof(sigmask)];
++  typename Traits::Char_64Only padding2[8];
++  typename Traits::MContext mcontext;
++};
++
++#if defined(ARCH_CPU_RISCV)
++static_assert(offsetof(UContext<ContextTraits32>, mcontext) ==
++                  offsetof(ucontext_t, uc_mcontext),
++              "context offset mismatch");
++static_assert(offsetof(UContext<ContextTraits32>, mcontext.gregs) ==
++                  offsetof(ucontext_t, uc_mcontext.__gregs),
++              "context offset mismatch");
++static_assert(offsetof(UContext<ContextTraits32>, mcontext.fpregs) ==
++                  offsetof(ucontext_t, uc_mcontext.__fpregs),
++              "context offset mismatch");
++#elif defined(ARCH_CPU_RISCV64)
++static_assert(offsetof(UContext<ContextTraits64>, mcontext) ==
++                  offsetof(ucontext_t, uc_mcontext),
++              "context offset mismatch");
++static_assert(offsetof(UContext<ContextTraits64>, mcontext.gregs) ==
++                  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");
++#endif
++
+ #else
+ #error Port.
+ #endif  // ARCH_CPU_X86_FAMILY
+diff --git a/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc
+index e77bcafa9c6b5..55564ae4aeaf5 100644
+--- a/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc
++++ b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc
+@@ -205,6 +205,9 @@ CPUArchitecture SystemSnapshotLinux::GetCPUArchitecture() const {
+ #elif defined(ARCH_CPU_MIPS_FAMILY)
+   return process_reader_->Is64Bit() ? kCPUArchitectureMIPS64EL
+                                     : kCPUArchitectureMIPSEL;
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++  return process_reader_->Is64Bit() ? kCPUArchitectureRISCV64
++                                    : kCPUArchitectureRISCV;
+ #else
+ #error port to your architecture
+ #endif
+@@ -220,6 +223,9 @@ uint32_t SystemSnapshotLinux::CPURevision() const {
+ #elif defined(ARCH_CPU_MIPS_FAMILY)
+   // Not implementable on MIPS
+   return 0;
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++  // Not implementable on RISCV
++  return 0;
+ #else
+ #error port to your architecture
+ #endif
+@@ -240,6 +246,9 @@ std::string SystemSnapshotLinux::CPUVendor() const {
+ #elif defined(ARCH_CPU_MIPS_FAMILY)
+   // Not implementable on MIPS
+   return std::string();
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++  // Not implementable on RISCV
++  return std::string();
+ #else
+ #error port to your architecture
+ #endif
+@@ -373,6 +382,9 @@ bool SystemSnapshotLinux::NXEnabled() const {
+ #elif defined(ARCH_CPU_MIPS_FAMILY)
+   // Not implementable on MIPS
+   return false;
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++  // Not implementable on RISCV
++  return false;
+ #else
+ #error Port.
+ #endif  // ARCH_CPU_X86_FAMILY
+diff --git a/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc
+index f279e0adaddba..8c133a7ca909f 100644
+--- a/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc
++++ b/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc
+@@ -189,6 +189,22 @@ bool ThreadSnapshotLinux::Initialize(
+         thread.thread_info.float_context.f32,
+         context_.mipsel);
+   }
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++  if (process_reader->Is64Bit()) {
++    context_.architecture = kCPUArchitectureRISCV64;
++    context_.riscv64 = &context_union_.riscv64;
++    InitializeCPUContextRISCV<ContextTraits64>(
++	thread.thread_info.thread_context.t64,
++	thread.thread_info.float_context.f64,
++	context_.riscv64);
++  } else {
++    context_.architecture = kCPUArchitectureRISCV;
++    context_.riscv = &context_union_.riscv;
++    InitializeCPUContextRISCV<ContextTraits32>(
++	thread.thread_info.thread_context.t32,
++	thread.thread_info.float_context.f32,
++	context_.riscv);
++  }
+ #else
+ #error Port.
+ #endif
+diff --git a/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h b/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h
+index 40cd7e7f54a39..aea1ce2047a6b 100644
+--- a/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h
++++ b/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h
+@@ -73,6 +73,9 @@ class ThreadSnapshotLinux final : public ThreadSnapshot {
+ #elif defined(ARCH_CPU_MIPS_FAMILY)
+     CPUContextMIPS mipsel;
+     CPUContextMIPS64 mips64;
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++    CPUContextRISCV riscv;
++    CPUContextRISCV64 riscv64;
+ #else
+ #error Port.
+ #endif  // ARCH_CPU_X86_FAMILY
+diff --git a/third_party/crashpad/crashpad/util/linux/ptracer.cc b/third_party/crashpad/crashpad/util/linux/ptracer.cc
+index 557e0d3635752..d74dbc1ba1688 100644
+--- a/third_party/crashpad/crashpad/util/linux/ptracer.cc
++++ b/third_party/crashpad/crashpad/util/linux/ptracer.cc
+@@ -397,6 +397,50 @@ bool GetThreadArea64(pid_t tid,
+   *address = FromPointerCast<LinuxVMAddress>(result);
+   return true;
+ }
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++
++template <typename Destination>
++bool GetRegisterSet(pid_t tid, int set, Destination* dest, bool can_log) {
++  iovec iov;
++  iov.iov_base = dest;
++  iov.iov_len = sizeof(*dest);
++  if (ptrace(PTRACE_GETREGSET, tid, reinterpret_cast<void*>(set), &iov) != 0) {
++    PLOG_IF(ERROR, can_log) << "ptrace";
++    return false;
++  }
++  if (iov.iov_len != sizeof(*dest)) {
++    LOG_IF(ERROR, can_log) << "Unexpected registers size";
++    return false;
++  }
++  return true;
++}
++
++bool GetFloatingPointRegisters32(pid_t tid,
++                                 FloatContext* context,
++                                 bool can_log) {
++  return false;
++}
++
++bool GetFloatingPointRegisters64(pid_t tid,
++                                 FloatContext* context,
++                                 bool can_log) {
++  return GetRegisterSet(tid, NT_PRFPREG, &context->f64.f, can_log);
++}
++
++bool GetThreadArea32(pid_t tid,
++                     const ThreadContext& context,
++                     LinuxVMAddress* address,
++                     bool can_log) {
++  return false;
++}
++
++bool GetThreadArea64(pid_t tid,
++                     const ThreadContext& context,
++                     LinuxVMAddress* address,
++                     bool can_log) {
++  *address = context.t64.tp;
++  return true;
++}
+ 
+ #else
+ #error Port.
+diff --git a/third_party/crashpad/crashpad/util/linux/thread_info.h b/third_party/crashpad/crashpad/util/linux/thread_info.h
+index d3f3b2c6953fa..6a649dc3d7ac7 100644
+--- a/third_party/crashpad/crashpad/util/linux/thread_info.h
++++ b/third_party/crashpad/crashpad/util/linux/thread_info.h
+@@ -79,6 +79,40 @@ union ThreadContext {
+     uint32_t cp0_status;
+     uint32_t cp0_cause;
+     uint32_t padding1_;
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++    // Reflects user_regs_struct in asm/ptrace.h.
++    uint32_t pc;
++    uint32_t ra;
++    uint32_t sp;
++    uint32_t gp;
++    uint32_t tp;
++    uint32_t t0;
++    uint32_t t1;
++    uint32_t t2;
++    uint32_t s0;
++    uint32_t s1;
++    uint32_t a0;
++    uint32_t a1;
++    uint32_t a2;
++    uint32_t a3;
++    uint32_t a4;
++    uint32_t a5;
++    uint32_t a6;
++    uint32_t a7;
++    uint32_t s2;
++    uint32_t s3;
++    uint32_t s4;
++    uint32_t s5;
++    uint32_t s6;
++    uint32_t s7;
++    uint32_t s8;
++    uint32_t s9;
++    uint32_t s10;
++    uint32_t s11;
++    uint32_t t3;
++    uint32_t t4;
++    uint32_t t5;
++    uint32_t t6;
+ #else
+ #error Port.
+ #endif  // ARCH_CPU_X86_FAMILY
+@@ -132,6 +166,40 @@ union ThreadContext {
+     uint64_t cp0_badvaddr;
+     uint64_t cp0_status;
+     uint64_t cp0_cause;
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++    // Reflects user_regs_struct in asm/ptrace.h.
++    uint64_t pc;
++    uint64_t ra;
++    uint64_t sp;
++    uint64_t gp;
++    uint64_t tp;
++    uint64_t t0;
++    uint64_t t1;
++    uint64_t t2;
++    uint64_t s0;
++    uint64_t s1;
++    uint64_t a0;
++    uint64_t a1;
++    uint64_t a2;
++    uint64_t a3;
++    uint64_t a4;
++    uint64_t a5;
++    uint64_t a6;
++    uint64_t a7;
++    uint64_t s2;
++    uint64_t s3;
++    uint64_t s4;
++    uint64_t s5;
++    uint64_t s6;
++    uint64_t s7;
++    uint64_t s8;
++    uint64_t s9;
++    uint64_t s10;
++    uint64_t s11;
++    uint64_t t3;
++    uint64_t t4;
++    uint64_t t5;
++    uint64_t t6;
+ #else
+ #error Port.
+ #endif  // ARCH_CPU_X86_FAMILY
+@@ -143,11 +211,12 @@ union ThreadContext {
+   using NativeThreadContext = user_regs;
+ #elif defined(ARCH_CPU_MIPS_FAMILY)
+ // No appropriate NativeThreadsContext type available for MIPS
++#elif defined(ARCH_CPU_RISCV_FAMILY)
+ #else
+ #error Port.
+ #endif  // ARCH_CPU_X86_FAMILY || ARCH_CPU_ARM64
+ 
+-#if !defined(ARCH_CPU_MIPS_FAMILY)
++#if !defined(ARCH_CPU_MIPS_FAMILY) && !defined(ARCH_CPU_RISCV_FAMILY)
+ #if defined(ARCH_CPU_32_BITS)
+   static_assert(sizeof(t32_t) == sizeof(NativeThreadContext), "Size mismatch");
+ #else  // ARCH_CPU_64_BITS
+@@ -218,6 +287,9 @@ union FloatContext {
+     } fpregs[32];
+     uint32_t fpcsr;
+     uint32_t fpu_id;
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++    uint64_t f[32];
++    uint32_t fcsr;
+ #else
+ #error Port.
+ #endif  // ARCH_CPU_X86_FAMILY
+@@ -252,6 +324,9 @@ union FloatContext {
+     double fpregs[32];
+     uint32_t fpcsr;
+     uint32_t fpu_id;
++#elif defined(ARCH_CPU_RISCV_FAMILY)
++    uint64_t f[32];
++    uint32_t fcsr;
+ #else
+ #error Port.
+ #endif  // ARCH_CPU_X86_FAMILY
+@@ -281,6 +356,7 @@ 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_RISCV_FAMILY)
+ #else
+ #error Port.
+ #endif  // ARCH_CPU_X86
+diff --git a/third_party/crashpad/crashpad/util/net/http_transport_libcurl.cc b/third_party/crashpad/crashpad/util/net/http_transport_libcurl.cc
+index 7e3f41186f462..9568dc2e24f97 100644
+--- a/third_party/crashpad/crashpad/util/net/http_transport_libcurl.cc
++++ b/third_party/crashpad/crashpad/util/net/http_transport_libcurl.cc
+@@ -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

+ 22 - 0
third_party/0012-third-party-highway-src.patch

@@ -0,0 +1,22 @@
+diff --git a/hwy/base.h b/hwy/base.h
+index d87eb34..db5df58 100644
+--- a/hwy/base.h
++++ b/hwy/base.h
+@@ -319,7 +319,7 @@ static constexpr HWY_MAYBE_UNUSED size_t kMaxVectorSize = 64;  // AVX-512
+ #elif HWY_ARCH_RVV
+ // Not actually an upper bound on the size, but this value prevents crossing a
+ // 4K boundary (relevant on Andes).
+-static constexpr HWY_MAYBE_UNUSED size_t kMaxVectorSize = 4096;
++static constexpr HWY_MAYBE_UNUSED size_t kMaxVectorSize = 64;
+ #define HWY_ALIGN_MAX alignas(8)  // only elements need be aligned
+ #else
+ static constexpr HWY_MAYBE_UNUSED size_t kMaxVectorSize = 16;
+@@ -333,7 +333,7 @@ static constexpr HWY_MAYBE_UNUSED size_t kMaxVectorSize = 16;
+ // by concatenating base type and bits.
+ 
+ // RVV already has a builtin type and the GCC intrinsics require it.
+-#if HWY_ARCH_RVV && HWY_COMPILER_GCC
++#if HWY_ARCH_RVV && HWY_COMPILER_GCC && 0
+ #define HWY_NATIVE_FLOAT16 1
+ #else
+ #define HWY_NATIVE_FLOAT16 0

+ 190 - 0
third_party/0013-third-party-lss.patch

@@ -0,0 +1,190 @@
+diff --git a/linux_syscall_support.h b/linux_syscall_support.h
+index 8d4e4d2..ce1345a 100644
+--- a/linux_syscall_support.h
++++ b/linux_syscall_support.h
+@@ -88,7 +88,7 @@
+  */
+ #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) ||   \
+      defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \
+-     defined(__aarch64__) || defined(__s390__)) || defined(__e2k__)  \
++     defined(__aarch64__) || defined(__s390__) || defined(__riscv)) || defined(__e2k__) \
+   && (defined(__linux) || defined(__ANDROID__))
+ 
+ #ifndef SYS_CPLUSPLUS
+@@ -302,7 +302,7 @@ struct kernel_old_sigaction {
+ } __attribute__((packed,aligned(4)));
+ #elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32)
+   #define kernel_old_sigaction kernel_sigaction
+-#elif defined(__aarch64__)
++#elif defined(__aarch64__) || defined(__riscv)
+   // No kernel_old_sigaction defined for arm64.
+ #endif
+ 
+@@ -542,7 +542,7 @@ struct kernel_stat {
+   int                st_blocks;
+   int                st_pad4[14];
+ };
+-#elif defined(__aarch64__)
++#elif defined(__aarch64__) || defined(__riscv)
+ struct kernel_stat {
+   unsigned long      st_dev;
+   unsigned long      st_ino;
+@@ -1110,7 +1110,7 @@ struct kernel_statfs {
+ #define __NR_getrandom          (__NR_SYSCALL_BASE + 384)
+ #endif
+ /* End of ARM 3/EABI definitions                                             */
+-#elif defined(__aarch64__)
++#elif defined(__aarch64__) || defined(__riscv)
+ #ifndef __NR_setxattr
+ #define __NR_setxattr             5
+ #endif
+@@ -1925,7 +1925,7 @@ struct kernel_statfs {
+ 
+   #undef  LSS_RETURN
+   #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \
+-       || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__)) \
++       || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__) || defined(__riscv)) \
+        || defined(__e2k__)
+   /* Failing system calls return a negative result in the range of
+    * -1..-4095. These are "errno" values with the sign inverted.
+@@ -3419,6 +3419,122 @@ struct kernel_statfs {
+       }
+       LSS_RETURN(int, __ret);
+     }
++  #elif defined(__riscv)
++    #undef LSS_REG
++    #define LSS_REG(r,a) register int64_t __r##r __asm__("a"#r) = (int64_t)a
++    #undef  LSS_BODY
++    #define LSS_BODY(type,name,args...)                                       \
++          register int64_t __res_a0 __asm__("a0");                           \
++          register int64_t __a7 __asm__("a7") = __NR_##name;                 \
++	  int64_t __res;                                                      \
++          __asm__ __volatile__ ("scall\n"                                     \
++                                : "=r"(__res_a0)                              \
++                                : "r"(__a7) , ## args                         \
++                                : "memory");                                  \
++          __res = __res_a0;                                                   \
++          LSS_RETURN(type, __res)
++    #undef _syscall0
++    #define _syscall0(type, name)                                             \
++      type LSS_NAME(name)(void) {                                             \
++        LSS_BODY(type, name);                                                 \
++      }
++    #undef _syscall1
++    #define _syscall1(type, name, type1, arg1)                                \
++      type LSS_NAME(name)(type1 arg1) {                                       \
++        LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0));                    \
++      }
++    #undef _syscall2
++    #define _syscall2(type, name, type1, arg1, type2, arg2)                   \
++      type LSS_NAME(name)(type1 arg1, type2 arg2) {                           \
++        LSS_REG(0, arg1); LSS_REG(1, arg2);                                   \
++        LSS_BODY(type, name, "r"(__r0), "r"(__r1));                           \
++      }
++    #undef _syscall3
++    #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3)      \
++      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) {               \
++        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
++        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2));                \
++      }
++    #undef _syscall4
++    #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)  \
++      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {   \
++        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
++        LSS_REG(3, arg4);                                                     \
++        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3));     \
++      }
++    #undef _syscall5
++    #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,  \
++                      type5,arg5)                                             \
++      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4,     \
++                          type5 arg5) {                                       \
++        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
++        LSS_REG(3, arg4); LSS_REG(4, arg5);                                   \
++        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3),      \
++                             "r"(__r4));                                      \
++      }
++    #undef _syscall6
++    #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,  \
++                      type5,arg5,type6,arg6)                                  \
++      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4,     \
++                          type5 arg5, type6 arg6) {                           \
++        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
++        LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6);                 \
++        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3),      \
++                             "r"(__r4), "r"(__r5));                           \
++      }
++
++    LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
++                                   int flags, void *arg, int *parent_tidptr,
++                                   void *newtls, int *child_tidptr) {
++      int64_t __res;
++      {
++        register int64_t __res_a0 __asm__("a0");
++        register uint64_t __flags __asm__("a0") = flags;
++        register void *__stack __asm__("a1") = child_stack;
++        register void *__ptid  __asm__("a2") = parent_tidptr;
++        register void *__tls   __asm__("a3") = newtls;
++        register int  *__ctid  __asm__("a4") = child_tidptr;
++        __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be
++                              * used by the child.
++                              */
++                             "addi    %2,%2,-16\n"
++			     "sd      %1, 0(%2)\n"
++			     "sd      %4, 8(%2)\n"
++
++                             /* %a0 = syscall(%a0 = flags,
++                              *               %a1 = child_stack,
++                              *               %a2 = parent_tidptr,
++                              *               %a3 = newtls,
++                              *               %a4 = child_tidptr)
++                              */
++                             "li      a7, %8\n"
++                             "scall\n"
++
++                             /* if (%a0 != 0)
++                              *   return %a0;
++                              */
++                             "bnez    %0, 1f\n"
++
++                             /* In the child, now. Call "fn(arg)".
++                              */
++                             "ld      a1, 0(sp)\n"
++                             "ld      a0, 8(sp)\n"
++                             "jalr    a1\n"
++
++                             /* Call _exit(%a0).
++                              */
++                             "li      a7, %9\n"
++                             "scall\n"
++                           "1:\n"
++                             : "=r" (__res_a0)
++                             : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg),
++                               "r"(__ptid), "r"(__tls), "r"(__ctid),
++                               "i"(__NR_clone), "i"(__NR_exit)
++                             : "cc", "memory");
++        __res = __res_a0;
++      }
++      LSS_RETURN(int, __res);
++    }
+   #elif defined(__e2k__)
+ 
+     #undef _LSS_BODY
+@@ -4484,7 +4600,7 @@ struct kernel_statfs {
+       LSS_SC_BODY(4, int, 8, d, type, protocol, sv);
+     }
+   #endif
+-  #if defined(__ARM_EABI__) || defined (__aarch64__)
++  #if defined(__ARM_EABI__) || defined (__aarch64__) || defined(__riscv)
+     LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg,
+                          int, flags)
+     LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*,
+@@ -4812,7 +4928,7 @@ struct kernel_statfs {
+ // TODO: define this in an arch-independant way instead of inlining the clone
+ //       syscall body.
+ 
+-# if defined(__aarch64__)
++# if defined(__aarch64__) || defined(__riscv)
+   LSS_INLINE pid_t LSS_NAME(fork)(void) {
+     // No fork syscall on aarch64 - implement by means of the clone syscall.
+     // Note that this does not reset glibc's cached view of the PID/TID, so