Add minimal riscv64 elf support to allow create_minidebuginfo on riscv64 binaries

This adds support for riscv64 elf files so that create_minidebuginfo
can be used strip riscv64 binaries.

Test: m create_minidebuginfo
Change-Id: I0cb0348d46ffb216af2f5c61701406504fae3b22
diff --git a/build/art.go b/build/art.go
index 7b06353..970af8a 100644
--- a/build/art.go
+++ b/build/art.go
@@ -95,12 +95,14 @@
 		cflags = append(cflags,
 			"-DART_STACK_OVERFLOW_GAP_arm=16384",
 			"-DART_STACK_OVERFLOW_GAP_arm64=16384",
+			"-DART_STACK_OVERFLOW_GAP_riscv64=16384",
 			"-DART_STACK_OVERFLOW_GAP_x86=16384",
 			"-DART_STACK_OVERFLOW_GAP_x86_64=20480")
 	} else {
 		cflags = append(cflags,
 			"-DART_STACK_OVERFLOW_GAP_arm=8192",
 			"-DART_STACK_OVERFLOW_GAP_arm64=8192",
+			"-DART_STACK_OVERFLOW_GAP_riscv64=8192",
 			"-DART_STACK_OVERFLOW_GAP_x86=8192",
 			"-DART_STACK_OVERFLOW_GAP_x86_64=8192")
 	}
diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h
index 094e887..269e3c6 100644
--- a/compiler/debug/elf_debug_frame_writer.h
+++ b/compiler/debug/elf_debug_frame_writer.h
@@ -88,6 +88,10 @@
       WriteCIE(is64bit, return_reg, opcodes, buffer);
       return;
     }
+    case InstructionSet::kRiscv64: {
+      UNIMPLEMENTED(FATAL);
+      return;
+    }
     case InstructionSet::kX86: {
       // FIXME: Add fp registers once libunwind adds support for them. Bug: 20491296
       constexpr bool generate_opcodes_for_x86_fp = false;
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index 8d62747..7df301a 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -73,6 +73,7 @@
         code_factor_bits_ = 2;  // 32-bit instructions
         break;
       case InstructionSet::kNone:
+      case InstructionSet::kRiscv64:
       case InstructionSet::kX86:
       case InstructionSet::kX86_64:
         break;
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
index 9be1e24..3742081 100644
--- a/compiler/debug/elf_debug_loc_writer.h
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -37,6 +37,8 @@
       return Reg::ArmCore(machine_reg);
     case InstructionSet::kArm64:
       return Reg::Arm64Core(machine_reg);
+    case InstructionSet::kRiscv64:
+      return Reg::Riscv64Core(machine_reg);
     case InstructionSet::kX86:
       return Reg::X86Core(machine_reg);
     case InstructionSet::kX86_64:
@@ -54,6 +56,8 @@
       return Reg::ArmFp(machine_reg);
     case InstructionSet::kArm64:
       return Reg::Arm64Fp(machine_reg);
+    case InstructionSet::kRiscv64:
+      return Reg::Riscv64Fp(machine_reg);
     case InstructionSet::kX86:
       return Reg::X86Fp(machine_reg);
     case InstructionSet::kX86_64:
diff --git a/libartbase/arch/instruction_set.cc b/libartbase/arch/instruction_set.cc
index 7f1e4c7..811e723 100644
--- a/libartbase/arch/instruction_set.cc
+++ b/libartbase/arch/instruction_set.cc
@@ -29,6 +29,7 @@
     case InstructionSet::kArm:
     case InstructionSet::kThumb2:
     case InstructionSet::kArm64:
+    case InstructionSet::kRiscv64:
     case InstructionSet::kX86:
     case InstructionSet::kX86_64:
     case InstructionSet::kNone:
@@ -46,6 +47,8 @@
       return "arm";
     case InstructionSet::kArm64:
       return "arm64";
+    case InstructionSet::kRiscv64:
+      return "riscv64";
     case InstructionSet::kX86:
       return "x86";
     case InstructionSet::kX86_64:
@@ -64,6 +67,8 @@
     return InstructionSet::kArm;
   } else if (strcmp("arm64", isa_str) == 0) {
     return InstructionSet::kArm64;
+  } else if (strcmp("riscv64", isa_str) == 0) {
+    return InstructionSet::kRiscv64;
   } else if (strcmp("x86", isa_str) == 0) {
     return InstructionSet::kX86;
   } else if (strcmp("x86_64", isa_str) == 0) {
@@ -93,6 +98,8 @@
         *error_msg = android::base::StringPrintf("Unknown Zygote kinds '%s'", zygote_kinds.c_str());
         return {};
       }
+    case InstructionSet::kRiscv64:
+      return {InstructionSet::kRiscv64};
     case InstructionSet::kX86:
     case InstructionSet::kX86_64:
       if (zygote_kinds == "zygote64_32" || zygote_kinds == "zygote32_64") {
diff --git a/libartbase/arch/instruction_set.h b/libartbase/arch/instruction_set.h
index e68ff08..8d59f1b 100644
--- a/libartbase/arch/instruction_set.h
+++ b/libartbase/arch/instruction_set.h
@@ -31,6 +31,7 @@
   kArm,
   kArm64,
   kThumb2,
+  kRiscv64,
   kX86,
   kX86_64,
   kLast = kX86_64
@@ -41,6 +42,8 @@
 static constexpr InstructionSet kRuntimeISA = InstructionSet::kArm;
 #elif defined(__aarch64__)
 static constexpr InstructionSet kRuntimeISA = InstructionSet::kArm64;
+#elif defined (__riscv)
+static constexpr InstructionSet kRuntimeISA = InstructionSet::kRiscv64;
 #elif defined(__i386__)
 static constexpr InstructionSet kRuntimeISA = InstructionSet::kX86;
 #elif defined(__x86_64__)
@@ -52,6 +55,7 @@
 // Architecture-specific pointer sizes
 static constexpr PointerSize kArmPointerSize = PointerSize::k32;
 static constexpr PointerSize kArm64PointerSize = PointerSize::k64;
+static constexpr PointerSize kRiscv64PointerSize = PointerSize::k64;
 static constexpr PointerSize kX86PointerSize = PointerSize::k32;
 static constexpr PointerSize kX86_64PointerSize = PointerSize::k64;
 
@@ -63,12 +67,17 @@
 // ARM processors require code to be 4-byte aligned, but ARM ELF requires 8.
 static constexpr size_t kArmCodeAlignment = 8;
 static constexpr size_t kArm64CodeAlignment = 16;
+static constexpr size_t kRiscv64CodeAlignment = 16;
 static constexpr size_t kX86CodeAlignment = 16;
 
 // Instruction alignment (every instruction must be aligned at this boundary). This differs from
 // code alignment, which applies only to the first instruction of a subroutine.
+// Android requires the RISC-V compressed instruction extension, and that allows
+// *all* instructions (not just compressed ones) to be 2-byte aligned rather
+// than the usual 4-byte alignment requirement.
 static constexpr size_t kThumb2InstructionAlignment = 2;
 static constexpr size_t kArm64InstructionAlignment = 4;
+static constexpr size_t kRiscv64InstructionAlignment = 2;
 static constexpr size_t kX86InstructionAlignment = 1;
 static constexpr size_t kX86_64InstructionAlignment = 1;
 
@@ -88,6 +97,8 @@
       return kArmPointerSize;
     case InstructionSet::kArm64:
       return kArm64PointerSize;
+    case InstructionSet::kRiscv64:
+      return kRiscv64PointerSize;
     case InstructionSet::kX86:
       return kX86PointerSize;
     case InstructionSet::kX86_64:
@@ -104,6 +115,7 @@
     case InstructionSet::kArm:
     case InstructionSet::kThumb2:
     case InstructionSet::kArm64:
+    case InstructionSet::kRiscv64:
     case InstructionSet::kX86:
     case InstructionSet::kX86_64:
       return true;
@@ -122,6 +134,8 @@
       return kThumb2InstructionAlignment;
     case InstructionSet::kArm64:
       return kArm64InstructionAlignment;
+    case InstructionSet::kRiscv64:
+      return kRiscv64InstructionAlignment;
     case InstructionSet::kX86:
       return kX86InstructionAlignment;
     case InstructionSet::kX86_64:
@@ -141,6 +155,8 @@
       return kArmCodeAlignment;
     case InstructionSet::kArm64:
       return kArm64CodeAlignment;
+    case InstructionSet::kRiscv64:
+      return kRiscv64CodeAlignment;
     case InstructionSet::kX86:
       // Fall-through.
     case InstructionSet::kX86_64:
@@ -158,6 +174,7 @@
   switch (isa) {
     case InstructionSet::kArm:
     case InstructionSet::kArm64:
+    case InstructionSet::kRiscv64:
     case InstructionSet::kX86:
     case InstructionSet::kX86_64:
       return 0;
@@ -180,6 +197,7 @@
       return false;
 
     case InstructionSet::kArm64:
+    case InstructionSet::kRiscv64:
     case InstructionSet::kX86_64:
       return true;
 
@@ -201,6 +219,8 @@
       return 4;
     case InstructionSet::kArm64:
       return 8;
+    case InstructionSet::kRiscv64:
+      return 8;
     case InstructionSet::kX86:
       return 4;
     case InstructionSet::kX86_64:
@@ -220,6 +240,8 @@
       return 4;
     case InstructionSet::kArm64:
       return 8;
+    case InstructionSet::kRiscv64:
+      return 8;
     case InstructionSet::kX86:
       return 8;
     case InstructionSet::kX86_64:
@@ -237,14 +259,16 @@
 namespace instruction_set_details {
 
 #if !defined(ART_STACK_OVERFLOW_GAP_arm) || !defined(ART_STACK_OVERFLOW_GAP_arm64) || \
+    !defined(ART_STACK_OVERFLOW_GAP_riscv64) || \
     !defined(ART_STACK_OVERFLOW_GAP_x86) || !defined(ART_STACK_OVERFLOW_GAP_x86_64)
 #error "Missing defines for stack overflow gap"
 #endif
 
-static constexpr size_t kArmStackOverflowReservedBytes    = ART_STACK_OVERFLOW_GAP_arm;
-static constexpr size_t kArm64StackOverflowReservedBytes  = ART_STACK_OVERFLOW_GAP_arm64;
-static constexpr size_t kX86StackOverflowReservedBytes    = ART_STACK_OVERFLOW_GAP_x86;
-static constexpr size_t kX86_64StackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_x86_64;
+static constexpr size_t kArmStackOverflowReservedBytes     = ART_STACK_OVERFLOW_GAP_arm;
+static constexpr size_t kArm64StackOverflowReservedBytes   = ART_STACK_OVERFLOW_GAP_arm64;
+static constexpr size_t kRiscv64StackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_riscv64;
+static constexpr size_t kX86StackOverflowReservedBytes     = ART_STACK_OVERFLOW_GAP_x86;
+static constexpr size_t kX86_64StackOverflowReservedBytes  = ART_STACK_OVERFLOW_GAP_x86_64;
 
 NO_RETURN void GetStackOverflowReservedBytesFailure(const char* error_msg);
 
@@ -260,6 +284,9 @@
     case InstructionSet::kArm64:
       return instruction_set_details::kArm64StackOverflowReservedBytes;
 
+    case InstructionSet::kRiscv64:
+      return instruction_set_details::kRiscv64StackOverflowReservedBytes;
+
     case InstructionSet::kX86:
       return instruction_set_details::kX86StackOverflowReservedBytes;
 
diff --git a/libelffile/dwarf/register.h b/libelffile/dwarf/register.h
index 7742ec4..33c6795 100644
--- a/libelffile/dwarf/register.h
+++ b/libelffile/dwarf/register.h
@@ -40,6 +40,8 @@
   static Reg ArmDp(int num) { return Reg(256 + num); }  // D0–D31.
   static Reg Arm64Core(int num) { return Reg(num); }  // X0-X31.
   static Reg Arm64Fp(int num) { return Reg(64 + num); }  // V0-V31.
+  static Reg Riscv64Core(int num) { return Reg(num); }  // X0-X31
+  static Reg Riscv64Fp(int num) { return Reg(32 + num); }  // F0-F31
   static Reg X86Core(int num) { return Reg(num); }
   static Reg X86Fp(int num) { return Reg(21 + num); }
   static Reg X86_64Core(int num) {
diff --git a/libelffile/elf/elf_builder.h b/libelffile/elf/elf_builder.h
index 086bd41..6720569 100644
--- a/libelffile/elf/elf_builder.h
+++ b/libelffile/elf/elf_builder.h
@@ -814,6 +814,8 @@
         return InstructionSet::kThumb2;
       case EM_AARCH64:
         return InstructionSet::kArm64;
+      case EM_RISCV:
+        return InstructionSet::kRiscv64;
       case EM_386:
         return InstructionSet::kX86;
       case EM_X86_64:
@@ -839,6 +841,11 @@
         elf_header.e_flags = 0;
         break;
       }
+      case InstructionSet::kRiscv64: {
+        elf_header.e_machine = EM_RISCV;
+        elf_header.e_flags = EF_RISCV_RVC | EF_RISCV_FLOAT_ABI_DOUBLE;
+        break;
+      }
       case InstructionSet::kX86: {
         elf_header.e_machine = EM_386;
         elf_header.e_flags = 0;
diff --git a/libelffile/elf/elf_utils.h b/libelffile/elf/elf_utils.h
index da67b8c..46b25b0 100644
--- a/libelffile/elf/elf_utils.h
+++ b/libelffile/elf/elf_utils.h
@@ -71,6 +71,15 @@
 
 #define EM_AARCH64 183
 
+#ifndef EM_RISCV
+#define EM_RISCV 243
+#endif
+
+#ifndef EF_RISCV_RVC
+#define EF_RISCV_RVC 0x1
+#define EF_RISCV_FLOAT_ABI_DOUBLE 0x4
+#endif
+
 #define DT_BIND_NOW 24
 #define DT_INIT_ARRAY 25
 #define DT_FINI_ARRAY 26
diff --git a/odrefresh/odr_config.h b/odrefresh/odr_config.h
index b262130..420f680 100644
--- a/odrefresh/odr_config.h
+++ b/odrefresh/odr_config.h
@@ -267,6 +267,7 @@
       case art::InstructionSet::kX86:
       case art::InstructionSet::kX86_64:
         return std::make_pair(art::InstructionSet::kX86, art::InstructionSet::kX86_64);
+      case art::InstructionSet::kRiscv64:
       case art::InstructionSet::kThumb2:
       case art::InstructionSet::kNone:
         LOG(FATAL) << "Invalid instruction set " << isa_;
diff --git a/runtime/metrics/statsd.cc b/runtime/metrics/statsd.cc
index 78c3622..203b72e 100644
--- a/runtime/metrics/statsd.cc
+++ b/runtime/metrics/statsd.cc
@@ -220,6 +220,8 @@
       return statsd::ART_DATUM_REPORTED__ISA__ART_ISA_ARM;
     case InstructionSet::kArm64:
       return statsd::ART_DATUM_REPORTED__ISA__ART_ISA_ARM64;
+    case InstructionSet::kRiscv64:
+      return statsd::ART_DATUM_REPORTED__ISA__ART_ISA_RISCV64;
     case InstructionSet::kX86:
       return statsd::ART_DATUM_REPORTED__ISA__ART_ISA_X86;
     case InstructionSet::kX86_64: