aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/diagnostics/s390/disasm-s390.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/diagnostics/s390/disasm-s390.cc')
-rw-r--r--deps/v8/src/diagnostics/s390/disasm-s390.cc1064
1 files changed, 1064 insertions, 0 deletions
diff --git a/deps/v8/src/diagnostics/s390/disasm-s390.cc b/deps/v8/src/diagnostics/s390/disasm-s390.cc
new file mode 100644
index 0000000000..9b10e236ce
--- /dev/null
+++ b/deps/v8/src/diagnostics/s390/disasm-s390.cc
@@ -0,0 +1,1064 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A Disassembler object is used to disassemble a block of code instruction by
+// instruction. The default implementation of the NameConverter object can be
+// overriden to modify register names or to do symbol lookup on addresses.
+//
+// The example below will disassemble a block of code and print it to stdout.
+//
+// NameConverter converter;
+// Disassembler d(converter);
+// for (byte* pc = begin; pc < end;) {
+// v8::internal::EmbeddedVector<char, 256> buffer;
+// byte* prev_pc = pc;
+// pc += d.InstructionDecode(buffer, pc);
+// printf("%p %08x %s\n",
+// prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
+// }
+//
+// The Disassembler class also has a convenience method to disassemble a block
+// of code into a FILE*, meaning that the above functionality could also be
+// achieved by just calling Disassembler::Disassemble(stdout, begin, end);
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#if V8_TARGET_ARCH_S390
+
+#include "src/base/platform/platform.h"
+#include "src/codegen/macro-assembler.h"
+#include "src/codegen/register-configuration.h"
+#include "src/codegen/s390/constants-s390.h"
+#include "src/diagnostics/disasm.h"
+
+namespace v8 {
+namespace internal {
+
+//------------------------------------------------------------------------------
+
+// Decoder decodes and disassembles instructions into an output buffer.
+// It uses the converter to convert register names and call destinations into
+// more informative description.
+class Decoder {
+ public:
+ Decoder(const disasm::NameConverter& converter, Vector<char> out_buffer)
+ : converter_(converter), out_buffer_(out_buffer), out_buffer_pos_(0) {
+ out_buffer_[out_buffer_pos_] = '\0';
+ }
+
+ ~Decoder() {}
+
+ // Writes one disassembled instruction into 'buffer' (0-terminated).
+ // Returns the length of the disassembled machine instruction in bytes.
+ int InstructionDecode(byte* instruction);
+
+ private:
+ // Bottleneck functions to print into the out_buffer.
+ void PrintChar(const char ch);
+ void Print(const char* str);
+
+ // Printing of common values.
+ void PrintRegister(int reg);
+ void PrintDRegister(int reg);
+ void PrintSoftwareInterrupt(SoftwareInterruptCodes svc);
+
+ // Handle formatting of instructions and their options.
+ int FormatRegister(Instruction* instr, const char* option);
+ int FormatFloatingRegister(Instruction* instr, const char* option);
+ int FormatMask(Instruction* instr, const char* option);
+ int FormatDisplacement(Instruction* instr, const char* option);
+ int FormatImmediate(Instruction* instr, const char* option);
+ int FormatOption(Instruction* instr, const char* option);
+ void Format(Instruction* instr, const char* format);
+ void Unknown(Instruction* instr);
+ void UnknownFormat(Instruction* instr, const char* opcname);
+
+ bool DecodeSpecial(Instruction* instr);
+ bool DecodeGeneric(Instruction* instr);
+
+ const disasm::NameConverter& converter_;
+ Vector<char> out_buffer_;
+ int out_buffer_pos_;
+
+ DISALLOW_COPY_AND_ASSIGN(Decoder);
+};
+
+// Support for assertions in the Decoder formatting functions.
+#define STRING_STARTS_WITH(string, compare_string) \
+ (strncmp(string, compare_string, strlen(compare_string)) == 0)
+
+// Append the ch to the output buffer.
+void Decoder::PrintChar(const char ch) { out_buffer_[out_buffer_pos_++] = ch; }
+
+// Append the str to the output buffer.
+void Decoder::Print(const char* str) {
+ char cur = *str++;
+ while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
+ PrintChar(cur);
+ cur = *str++;
+ }
+ out_buffer_[out_buffer_pos_] = 0;
+}
+
+// Print the register name according to the active name converter.
+void Decoder::PrintRegister(int reg) {
+ Print(converter_.NameOfCPURegister(reg));
+}
+
+// Print the double FP register name according to the active name converter.
+void Decoder::PrintDRegister(int reg) {
+ Print(RegisterName(DoubleRegister::from_code(reg)));
+}
+
+// Print SoftwareInterrupt codes. Factoring this out reduces the complexity of
+// the FormatOption method.
+void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) {
+ switch (svc) {
+ case kCallRtRedirected:
+ Print("call rt redirected");
+ return;
+ case kBreakpoint:
+ Print("breakpoint");
+ return;
+ default:
+ if (svc >= kStopCode) {
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d - 0x%x",
+ svc & kStopCodeMask, svc & kStopCodeMask);
+ } else {
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", svc);
+ }
+ return;
+ }
+}
+
+// Handle all register based formatting in this function to reduce the
+// complexity of FormatOption.
+int Decoder::FormatRegister(Instruction* instr, const char* format) {
+ DCHECK_EQ(format[0], 'r');
+
+ if (format[1] == '1') { // 'r1: register resides in bit 8-11
+ int reg = instr->Bits<SixByteInstr, int>(39, 36);
+ PrintRegister(reg);
+ return 2;
+ } else if (format[1] == '2') { // 'r2: register resides in bit 12-15
+ int reg = instr->Bits<SixByteInstr, int>(35, 32);
+ // indicating it is a r0 for displacement, in which case the offset
+ // should be 0.
+ if (format[2] == 'd') {
+ if (reg == 0) return 4;
+ PrintRegister(reg);
+ return 3;
+ } else {
+ PrintRegister(reg);
+ return 2;
+ }
+ } else if (format[1] == '3') { // 'r3: register resides in bit 16-19
+ int reg = instr->Bits<SixByteInstr, int>(31, 28);
+ PrintRegister(reg);
+ return 2;
+ } else if (format[1] == '4') { // 'r4: register resides in bit 20-23
+ int reg = instr->Bits<SixByteInstr, int>(27, 24);
+ PrintRegister(reg);
+ return 2;
+ } else if (format[1] == '5') { // 'r5: register resides in bit 24-27
+ int reg = instr->Bits<SixByteInstr, int>(23, 20);
+ PrintRegister(reg);
+ return 2;
+ } else if (format[1] == '6') { // 'r6: register resides in bit 28-31
+ int reg = instr->Bits<SixByteInstr, int>(19, 16);
+ PrintRegister(reg);
+ return 2;
+ } else if (format[1] == '7') { // 'r6: register resides in bit 32-35
+ int reg = instr->Bits<SixByteInstr, int>(15, 12);
+ PrintRegister(reg);
+ return 2;
+ }
+
+ UNREACHABLE();
+}
+
+int Decoder::FormatFloatingRegister(Instruction* instr, const char* format) {
+ DCHECK_EQ(format[0], 'f');
+
+ // reuse 1, 5 and 6 because it is coresponding
+ if (format[1] == '1') { // 'r1: register resides in bit 8-11
+ RRInstruction* rrinstr = reinterpret_cast<RRInstruction*>(instr);
+ int reg = rrinstr->R1Value();
+ PrintDRegister(reg);
+ return 2;
+ } else if (format[1] == '2') { // 'f2: register resides in bit 12-15
+ RRInstruction* rrinstr = reinterpret_cast<RRInstruction*>(instr);
+ int reg = rrinstr->R2Value();
+ PrintDRegister(reg);
+ return 2;
+ } else if (format[1] == '3') { // 'f3: register resides in bit 16-19
+ RRDInstruction* rrdinstr = reinterpret_cast<RRDInstruction*>(instr);
+ int reg = rrdinstr->R1Value();
+ PrintDRegister(reg);
+ return 2;
+ } else if (format[1] == '5') { // 'f5: register resides in bit 24-28
+ RREInstruction* rreinstr = reinterpret_cast<RREInstruction*>(instr);
+ int reg = rreinstr->R1Value();
+ PrintDRegister(reg);
+ return 2;
+ } else if (format[1] == '6') { // 'f6: register resides in bit 29-32
+ RREInstruction* rreinstr = reinterpret_cast<RREInstruction*>(instr);
+ int reg = rreinstr->R2Value();
+ PrintDRegister(reg);
+ return 2;
+ } else if (format[1] == '4') {
+ VRR_E_Instruction* vrreinstr = reinterpret_cast<VRR_E_Instruction*>(instr);
+ int reg = vrreinstr->R4Value();
+ PrintDRegister(reg);
+ return 2;
+ }
+ UNREACHABLE();
+}
+
+// FormatOption takes a formatting string and interprets it based on
+// the current instructions. The format string points to the first
+// character of the option string (the option escape has already been
+// consumed by the caller.) FormatOption returns the number of
+// characters that were consumed from the formatting string.
+int Decoder::FormatOption(Instruction* instr, const char* format) {
+ switch (format[0]) {
+ case 'o': {
+ if (instr->Bit(10) == 1) {
+ Print("o");
+ }
+ return 1;
+ }
+ case '.': {
+ if (instr->Bit(0) == 1) {
+ Print(".");
+ } else {
+ Print(" "); // ensure consistent spacing
+ }
+ return 1;
+ }
+ case 'r': {
+ return FormatRegister(instr, format);
+ }
+ case 'f': {
+ return FormatFloatingRegister(instr, format);
+ }
+ case 'i': { // int16
+ return FormatImmediate(instr, format);
+ }
+ case 'u': { // uint16
+ int32_t value = instr->Bits(15, 0);
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 6;
+ }
+ case 'l': {
+ // Link (LK) Bit 0
+ if (instr->Bit(0) == 1) {
+ Print("l");
+ }
+ return 1;
+ }
+ case 'a': {
+ // Absolute Address Bit 1
+ if (instr->Bit(1) == 1) {
+ Print("a");
+ }
+ return 1;
+ }
+ case 't': { // 'target: target of branch instructions
+ // target26 or target16
+ DCHECK(STRING_STARTS_WITH(format, "target"));
+ if ((format[6] == '2') && (format[7] == '6')) {
+ int off = ((instr->Bits(25, 2)) << 8) >> 6;
+ out_buffer_pos_ += SNPrintF(
+ out_buffer_ + out_buffer_pos_, "%+d -> %s", off,
+ converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
+ return 8;
+ } else if ((format[6] == '1') && (format[7] == '6')) {
+ int off = ((instr->Bits(15, 2)) << 18) >> 16;
+ out_buffer_pos_ += SNPrintF(
+ out_buffer_ + out_buffer_pos_, "%+d -> %s", off,
+ converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
+ return 8;
+ }
+ break;
+ case 'm': {
+ return FormatMask(instr, format);
+ }
+ }
+ case 'd': { // ds value for offset
+ return FormatDisplacement(instr, format);
+ }
+ default: {
+ UNREACHABLE();
+ }
+ }
+
+ UNREACHABLE();
+}
+
+int Decoder::FormatMask(Instruction* instr, const char* format) {
+ DCHECK_EQ(format[0], 'm');
+ int32_t value = 0;
+ if ((format[1] == '1')) { // prints the mask format in bits 8-12
+ value = reinterpret_cast<RRInstruction*>(instr)->R1Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
+ return 2;
+ } else if (format[1] == '2') { // mask format in bits 16-19
+ value = reinterpret_cast<RXInstruction*>(instr)->B2Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
+ return 2;
+ } else if (format[1] == '3') { // mask format in bits 20-23
+ value = reinterpret_cast<RRFInstruction*>(instr)->M4Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
+ return 2;
+ } else if (format[1] == '4') { // mask format in bits 32-35
+ value = reinterpret_cast<VRR_C_Instruction*>(instr)->M4Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
+ return 2;
+ } else if (format[1] == '5') { // mask format in bits 28-31
+ value = reinterpret_cast<VRR_C_Instruction*>(instr)->M5Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
+ return 2;
+ } else if (format[1] == '6') { // mask format in bits 24-27
+ value = reinterpret_cast<VRR_C_Instruction*>(instr)->M6Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
+ return 2;
+ }
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+}
+
+int Decoder::FormatDisplacement(Instruction* instr, const char* format) {
+ DCHECK_EQ(format[0], 'd');
+
+ if (format[1] == '1') { // displacement in 20-31
+ RSInstruction* rsinstr = reinterpret_cast<RSInstruction*>(instr);
+ uint16_t value = rsinstr->D2Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+
+ return 2;
+ } else if (format[1] == '2') { // displacement in 20-39
+ RXYInstruction* rxyinstr = reinterpret_cast<RXYInstruction*>(instr);
+ int32_t value = rxyinstr->D2Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == '4') { // SS displacement 2 36-47
+ SSInstruction* ssInstr = reinterpret_cast<SSInstruction*>(instr);
+ uint16_t value = ssInstr->D2Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == '3') { // SS displacement 1 20 - 32
+ SSInstruction* ssInstr = reinterpret_cast<SSInstruction*>(instr);
+ uint16_t value = ssInstr->D1Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else { // s390 specific
+ int32_t value = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3);
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 1;
+ }
+}
+
+int Decoder::FormatImmediate(Instruction* instr, const char* format) {
+ DCHECK_EQ(format[0], 'i');
+
+ if (format[1] == '1') { // immediate in 16-31
+ RIInstruction* riinstr = reinterpret_cast<RIInstruction*>(instr);
+ int16_t value = riinstr->I2Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == '2') { // immediate in 16-48
+ RILInstruction* rilinstr = reinterpret_cast<RILInstruction*>(instr);
+ int32_t value = rilinstr->I2Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == '3') { // immediate in I format
+ IInstruction* iinstr = reinterpret_cast<IInstruction*>(instr);
+ int8_t value = iinstr->IValue();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == '4') { // immediate in 16-31, but outputs as offset
+ RIInstruction* riinstr = reinterpret_cast<RIInstruction*>(instr);
+ int16_t value = riinstr->I2Value() * 2;
+ if (value >= 0)
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*+");
+ else
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*");
+
+ out_buffer_pos_ += SNPrintF(
+ out_buffer_ + out_buffer_pos_, "%d -> %s", value,
+ converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + value));
+ return 2;
+ } else if (format[1] == '5') { // immediate in 16-31, but outputs as offset
+ RILInstruction* rilinstr = reinterpret_cast<RILInstruction*>(instr);
+ int32_t value = rilinstr->I2Value() * 2;
+ if (value >= 0)
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*+");
+ else
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*");
+
+ out_buffer_pos_ += SNPrintF(
+ out_buffer_ + out_buffer_pos_, "%d -> %s", value,
+ converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + value));
+ return 2;
+ } else if (format[1] == '6') { // unsigned immediate in 16-31
+ RIInstruction* riinstr = reinterpret_cast<RIInstruction*>(instr);
+ uint16_t value = riinstr->I2UnsignedValue();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == '7') { // unsigned immediate in 16-47
+ RILInstruction* rilinstr = reinterpret_cast<RILInstruction*>(instr);
+ uint32_t value = rilinstr->I2UnsignedValue();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == '8') { // unsigned immediate in 8-15
+ SSInstruction* ssinstr = reinterpret_cast<SSInstruction*>(instr);
+ uint8_t value = ssinstr->Length();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == '9') { // unsigned immediate in 16-23
+ RIEInstruction* rie_instr = reinterpret_cast<RIEInstruction*>(instr);
+ uint8_t value = rie_instr->I3Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == 'a') { // unsigned immediate in 24-31
+ RIEInstruction* rie_instr = reinterpret_cast<RIEInstruction*>(instr);
+ uint8_t value = rie_instr->I4Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == 'b') { // unsigned immediate in 32-39
+ RIEInstruction* rie_instr = reinterpret_cast<RIEInstruction*>(instr);
+ uint8_t value = rie_instr->I5Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == 'c') { // signed immediate in 8-15
+ SSInstruction* ssinstr = reinterpret_cast<SSInstruction*>(instr);
+ int8_t value = ssinstr->Length();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == 'd') { // signed immediate in 32-47
+ SILInstruction* silinstr = reinterpret_cast<SILInstruction*>(instr);
+ int16_t value = silinstr->I2Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+ return 2;
+ } else if (format[1] == 'e') { // immediate in 16-47, but outputs as offset
+ RILInstruction* rilinstr = reinterpret_cast<RILInstruction*>(instr);
+ int32_t value = rilinstr->I2Value() * 2;
+ if (value >= 0)
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*+");
+ else
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*");
+
+ out_buffer_pos_ += SNPrintF(
+ out_buffer_ + out_buffer_pos_, "%d -> %s", value,
+ converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + value));
+ return 2;
+ }
+
+ UNREACHABLE();
+}
+
+// Format takes a formatting string for a whole instruction and prints it into
+// the output buffer. All escaped options are handed to FormatOption to be
+// parsed further.
+void Decoder::Format(Instruction* instr, const char* format) {
+ char cur = *format++;
+ while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
+ if (cur == '\'') { // Single quote is used as the formatting escape.
+ format += FormatOption(instr, format);
+ } else {
+ out_buffer_[out_buffer_pos_++] = cur;
+ }
+ cur = *format++;
+ }
+ out_buffer_[out_buffer_pos_] = '\0';
+}
+
+// The disassembler may end up decoding data inlined in the code. We do not want
+// it to crash if the data does not resemble any known instruction.
+#define VERIFY(condition) \
+ if (!(condition)) { \
+ Unknown(instr); \
+ return; \
+ }
+
+// For currently unimplemented decodings the disassembler calls Unknown(instr)
+// which will just print "unknown" of the instruction bits.
+void Decoder::Unknown(Instruction* instr) { Format(instr, "unknown"); }
+
+// For currently unimplemented decodings the disassembler calls
+// UnknownFormat(instr) which will just print opcode name of the
+// instruction bits.
+void Decoder::UnknownFormat(Instruction* instr, const char* name) {
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "%s (unknown-format)", name);
+ Format(instr, buffer);
+}
+
+#undef VERIFY
+#undef STRING_STARTS_WITH
+
+// Handles special cases of instructions;
+// @return true if successfully decoded
+bool Decoder::DecodeSpecial(Instruction* instr) {
+ Opcode opcode = instr->S390OpcodeValue();
+ switch (opcode) {
+ case BKPT:
+ Format(instr, "bkpt");
+ break;
+ case DUMY:
+ Format(instr, "dumy\t'r1, 'd2 ( 'r2d, 'r3 )");
+ break;
+ /* RR format */
+ case LDR:
+ Format(instr, "ldr\t'f1,'f2");
+ break;
+ case BCR:
+ Format(instr, "bcr\t'm1,'r2");
+ break;
+ case OR:
+ Format(instr, "or\t'r1,'r2");
+ break;
+ case CR:
+ Format(instr, "cr\t'r1,'r2");
+ break;
+ case MR:
+ Format(instr, "mr\t'r1,'r2");
+ break;
+ case HER_Z:
+ Format(instr, "her\t'r1,'r2");
+ break;
+ /* RI-b format */
+ case BRAS:
+ Format(instr, "bras\t'r1,'i1");
+ break;
+ /* RRE format */
+ case MDBR:
+ Format(instr, "mdbr\t'f5,'f6");
+ break;
+ case SDBR:
+ Format(instr, "sdbr\t'f5,'f6");
+ break;
+ case ADBR:
+ Format(instr, "adbr\t'f5,'f6");
+ break;
+ case CDBR:
+ Format(instr, "cdbr\t'f5,'f6");
+ break;
+ case MEEBR:
+ Format(instr, "meebr\t'f5,'f6");
+ break;
+ case SQDBR:
+ Format(instr, "sqdbr\t'f5,'f6");
+ break;
+ case SQEBR:
+ Format(instr, "sqebr\t'f5,'f6");
+ break;
+ case LCDBR:
+ Format(instr, "lcdbr\t'f5,'f6");
+ break;
+ case LCEBR:
+ Format(instr, "lcebr\t'f5,'f6");
+ break;
+ case LTEBR:
+ Format(instr, "ltebr\t'f5,'f6");
+ break;
+ case LDEBR:
+ Format(instr, "ldebr\t'f5,'f6");
+ break;
+ case CEBR:
+ Format(instr, "cebr\t'f5,'f6");
+ break;
+ case AEBR:
+ Format(instr, "aebr\t'f5,'f6");
+ break;
+ case SEBR:
+ Format(instr, "sebr\t'f5,'f6");
+ break;
+ case DEBR:
+ Format(instr, "debr\t'f5,'f6");
+ break;
+ case LTDBR:
+ Format(instr, "ltdbr\t'f5,'f6");
+ break;
+ case LDGR:
+ Format(instr, "ldgr\t'f5,'f6");
+ break;
+ case DDBR:
+ Format(instr, "ddbr\t'f5,'f6");
+ break;
+ case LZDR:
+ Format(instr, "lzdr\t'f5");
+ break;
+ /* RRF-e format */
+ case FIEBRA:
+ Format(instr, "fiebra\t'f5,'m2,'f6,'m3");
+ break;
+ case FIDBRA:
+ Format(instr, "fidbra\t'f5,'m2,'f6,'m3");
+ break;
+ /* RX-a format */
+ case IC_z:
+ Format(instr, "ic\t'r1,'d1('r2d,'r3)");
+ break;
+ case AL:
+ Format(instr, "al\t'r1,'d1('r2d,'r3)");
+ break;
+ case LE:
+ Format(instr, "le\t'f1,'d1('r2d,'r3)");
+ break;
+ case LD:
+ Format(instr, "ld\t'f1,'d1('r2d,'r3)");
+ break;
+ case STE:
+ Format(instr, "ste\t'f1,'d1('r2d,'r3)");
+ break;
+ case STD:
+ Format(instr, "std\t'f1,'d1('r2d,'r3)");
+ break;
+ /* S format */
+ // TRAP4 is used in calling to native function. it will not be generated
+ // in native code.
+ case TRAP4:
+ Format(instr, "trap4");
+ break;
+ /* RIL-a format */
+ case CFI:
+ Format(instr, "cfi\t'r1,'i2");
+ break;
+ case CGFI:
+ Format(instr, "cgfi\t'r1,'i2");
+ break;
+ case AFI:
+ Format(instr, "afi\t'r1,'i2");
+ break;
+ case AGFI:
+ Format(instr, "agfi\t'r1,'i2");
+ break;
+ case MSFI:
+ Format(instr, "msfi\t'r1,'i2");
+ break;
+ case MSGFI:
+ Format(instr, "msgfi\t'r1,'i2");
+ break;
+ case ALSIH:
+ Format(instr, "alsih\t'r1,'i2");
+ break;
+ case ALSIHN:
+ Format(instr, "alsihn\t'r1,'i2");
+ break;
+ case CIH:
+ Format(instr, "cih\t'r1,'i2");
+ break;
+ case AIH:
+ Format(instr, "aih\t'r1,'i2");
+ break;
+ case LGFI:
+ Format(instr, "lgfi\t'r1,'i2");
+ break;
+ /* SIY format */
+ case ASI:
+ Format(instr, "asi\t'd2('r3),'ic");
+ break;
+ case AGSI:
+ Format(instr, "agsi\t'd2('r3),'ic");
+ break;
+ /* RXY-a format */
+ case LT:
+ Format(instr, "lt\t'r1,'d2('r2d,'r3)");
+ break;
+ case LDY:
+ Format(instr, "ldy\t'f1,'d2('r2d,'r3)");
+ break;
+ case LEY:
+ Format(instr, "ley\t'f1,'d2('r2d,'r3)");
+ break;
+ case STDY:
+ Format(instr, "stdy\t'f1,'d2('r2d,'r3)");
+ break;
+ case STEY:
+ Format(instr, "stey\t'f1,'d2('r2d,'r3)");
+ break;
+ /* RXE format */
+ case LDEB:
+ Format(instr, "ldeb\t'f1,'d2('r2d,'r3)");
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+// Handles common cases of instructions;
+// @return true if successfully decoded
+bool Decoder::DecodeGeneric(Instruction* instr) {
+ Opcode opcode = instr->S390OpcodeValue();
+ switch (opcode) {
+ /* 2 bytes */
+#define DECODE_RR_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'r2"); \
+ break;
+ S390_RR_OPCODE_LIST(DECODE_RR_INSTRUCTIONS)
+#undef DECODE_RR_INSTRUCTIONS
+
+ /* 4 bytes */
+#define DECODE_RS_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'r2,'d1('r3)"); \
+ break;
+ S390_RS_A_OPCODE_LIST(DECODE_RS_A_INSTRUCTIONS)
+#undef DECODE_RS_A_INSTRUCTIONS
+
+#define DECODE_RSI_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'r2,'i4"); \
+ break;
+ S390_RSI_OPCODE_LIST(DECODE_RSI_INSTRUCTIONS)
+#undef DECODE_RSI_INSTRUCTIONS
+
+#define DECODE_RI_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'i1"); \
+ break;
+ S390_RI_A_OPCODE_LIST(DECODE_RI_A_INSTRUCTIONS)
+#undef DECODE_RI_A_INSTRUCTIONS
+
+#define DECODE_RI_B_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'i4"); \
+ break;
+ S390_RI_B_OPCODE_LIST(DECODE_RI_B_INSTRUCTIONS)
+#undef DECODE_RI_B_INSTRUCTIONS
+
+#define DECODE_RI_C_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'm1,'i4"); \
+ break;
+ S390_RI_C_OPCODE_LIST(DECODE_RI_C_INSTRUCTIONS)
+#undef DECODE_RI_C_INSTRUCTIONS
+
+#define DECODE_RRE_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r5,'r6"); \
+ break;
+ S390_RRE_OPCODE_LIST(DECODE_RRE_INSTRUCTIONS)
+#undef DECODE_RRE_INSTRUCTIONS
+
+#define DECODE_RRF_A_INSTRUCTIONS(name, opcode_name, opcode_val) \
+ case opcode_name: \
+ Format(instr, #name "\t'r5,'r6,'r3"); \
+ break;
+ S390_RRF_A_OPCODE_LIST(DECODE_RRF_A_INSTRUCTIONS)
+#undef DECODE_RRF_A_INSTRUCTIONS
+
+#define DECODE_RRF_C_INSTRUCTIONS(name, opcode_name, opcode_val) \
+ case opcode_name: \
+ Format(instr, #name "\t'r5,'r6,'m2"); \
+ break;
+ S390_RRF_C_OPCODE_LIST(DECODE_RRF_C_INSTRUCTIONS)
+#undef DECODE_RRF_C_INSTRUCTIONS
+
+#define DECODE_RRF_E_INSTRUCTIONS(name, opcode_name, opcode_val) \
+ case opcode_name: \
+ Format(instr, #name "\t'r5,'m2,'f6"); \
+ break;
+ S390_RRF_E_OPCODE_LIST(DECODE_RRF_E_INSTRUCTIONS)
+#undef DECODE_RRF_E_INSTRUCTIONS
+
+#define DECODE_RX_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'d1('r2d,'r3)"); \
+ break;
+ S390_RX_A_OPCODE_LIST(DECODE_RX_A_INSTRUCTIONS)
+#undef DECODE_RX_A_INSTRUCTIONS
+
+#define DECODE_RX_B_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'm1,'d1('r2d,'r3)"); \
+ break;
+ S390_RX_B_OPCODE_LIST(DECODE_RX_B_INSTRUCTIONS)
+#undef DECODE_RX_B_INSTRUCTIONS
+
+#define DECODE_RRD_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f3,'f5,'f6"); \
+ break;
+ S390_RRD_OPCODE_LIST(DECODE_RRD_INSTRUCTIONS)
+#undef DECODE_RRD_INSTRUCTIONS
+
+#define DECODE_SI_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'd1('r3),'i8"); \
+ break;
+ S390_SI_OPCODE_LIST(DECODE_SI_INSTRUCTIONS)
+#undef DECODE_SI_INSTRUCTIONS
+
+ /* 6 bytes */
+#define DECODE_VRR_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f1,'f2,'m4,'m5,'m6"); \
+ break;
+ S390_VRR_A_OPCODE_LIST(DECODE_VRR_A_INSTRUCTIONS)
+#undef DECODE_VRR_A_INSTRUCTIONS
+
+#define DECODE_VRR_B_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f1,'f2,'f3,'m4,'m6"); \
+ break;
+ S390_VRR_B_OPCODE_LIST(DECODE_VRR_B_INSTRUCTIONS)
+#undef DECODE_VRR_B_INSTRUCTIONS
+
+#define DECODE_VRR_C_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f1,'f2,'f3,'m4"); \
+ break;
+ S390_VRR_C_OPCODE_LIST(DECODE_VRR_C_INSTRUCTIONS)
+#undef DECODE_VRR_C_INSTRUCTIONS
+
+#define DECODE_VRR_E_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f1,'f2,'f3,'f4,'m5,'m3"); \
+ break;
+ S390_VRR_E_OPCODE_LIST(DECODE_VRR_E_INSTRUCTIONS)
+#undef DECODE_VRR_E_INSTRUCTIONS
+
+#define DECODE_VRX_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f1,'d1('r2d,'r3),'m4"); \
+ break;
+ S390_VRX_OPCODE_LIST(DECODE_VRX_INSTRUCTIONS)
+#undef DECODE_VRX_INSTRUCTIONS
+
+#define DECODE_VRS_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f1,'f2,'d1('r3),'m4"); \
+ break;
+ S390_VRS_A_OPCODE_LIST(DECODE_VRS_A_INSTRUCTIONS)
+#undef DECODE_VRS_A_INSTRUCTIONS
+
+#define DECODE_VRS_B_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f1,'r2,'d1('r3),'m4"); \
+ break;
+ S390_VRS_B_OPCODE_LIST(DECODE_VRS_B_INSTRUCTIONS)
+#undef DECODE_VRS_B_INSTRUCTIONS
+
+#define DECODE_VRS_C_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'f2,'d1('r3),'m4"); \
+ break;
+ S390_VRS_C_OPCODE_LIST(DECODE_VRS_C_INSTRUCTIONS)
+#undef DECODE_VRS_C_INSTRUCTIONS
+
+#define DECODE_VRI_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f1,'i1,'m4"); \
+ break;
+ S390_VRI_A_OPCODE_LIST(DECODE_VRI_A_INSTRUCTIONS)
+#undef DECODE_VRI_A_INSTRUCTIONS
+
+#define DECODE_VRI_C_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f1,'f2,'i1,'m4"); \
+ break;
+ S390_VRI_C_OPCODE_LIST(DECODE_VRI_C_INSTRUCTIONS)
+#undef DECODE_VRI_C_INSTRUCTIONS
+
+#define DECODE_RIL_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'i7"); \
+ break;
+ S390_RIL_A_OPCODE_LIST(DECODE_RIL_A_INSTRUCTIONS)
+#undef DECODE_RIL_A_INSTRUCTIONS
+
+#define DECODE_RIL_B_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'ie"); \
+ break;
+ S390_RIL_B_OPCODE_LIST(DECODE_RIL_B_INSTRUCTIONS)
+#undef DECODE_RIL_B_INSTRUCTIONS
+
+#define DECODE_RIL_C_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'm1,'ie"); \
+ break;
+ S390_RIL_C_OPCODE_LIST(DECODE_RIL_C_INSTRUCTIONS)
+#undef DECODE_RIL_C_INSTRUCTIONS
+
+#define DECODE_SIY_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'd2('r3),'i8"); \
+ break;
+ S390_SIY_OPCODE_LIST(DECODE_SIY_INSTRUCTIONS)
+#undef DECODE_SIY_INSTRUCTIONS
+
+#define DECODE_RIE_D_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'r2,'i1"); \
+ break;
+ S390_RIE_D_OPCODE_LIST(DECODE_RIE_D_INSTRUCTIONS)
+#undef DECODE_RIE_D_INSTRUCTIONS
+
+#define DECODE_RIE_E_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'r2,'i4"); \
+ break;
+ S390_RIE_E_OPCODE_LIST(DECODE_RIE_E_INSTRUCTIONS)
+#undef DECODE_RIE_E_INSTRUCTIONS
+
+#define DECODE_RIE_F_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'r2,'i9,'ia,'ib"); \
+ break;
+ S390_RIE_F_OPCODE_LIST(DECODE_RIE_F_INSTRUCTIONS)
+#undef DECODE_RIE_F_INSTRUCTIONS
+
+#define DECODE_RSY_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'r2,'d2('r3)"); \
+ break;
+ S390_RSY_A_OPCODE_LIST(DECODE_RSY_A_INSTRUCTIONS)
+#undef DECODE_RSY_A_INSTRUCTIONS
+
+#define DECODE_RSY_B_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'm2,'r1,'d2('r3)"); \
+ break;
+ S390_RSY_B_OPCODE_LIST(DECODE_RSY_B_INSTRUCTIONS)
+#undef DECODE_RSY_B_INSTRUCTIONS
+
+#define DECODE_RXY_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'r1,'d2('r2d,'r3)"); \
+ break;
+ S390_RXY_A_OPCODE_LIST(DECODE_RXY_A_INSTRUCTIONS)
+#undef DECODE_RXY_A_INSTRUCTIONS
+
+#define DECODE_RXY_B_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'm1,'d2('r2d,'r3)"); \
+ break;
+ S390_RXY_B_OPCODE_LIST(DECODE_RXY_B_INSTRUCTIONS)
+#undef DECODE_RXY_B_INSTRUCTIONS
+
+#define DECODE_RXE_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'f1,'d1('r2d, 'r3)"); \
+ break;
+ S390_RXE_OPCODE_LIST(DECODE_RXE_INSTRUCTIONS)
+#undef DECODE_RXE_INSTRUCTIONS
+
+#define DECODE_SIL_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'd3('r3),'id"); \
+ break;
+ S390_SIL_OPCODE_LIST(DECODE_SIL_INSTRUCTIONS)
+#undef DECODE_SIL_INSTRUCTIONS
+
+#define DECODE_SS_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
+ case opcode_name: \
+ Format(instr, #name "\t'd3('i8,'r3),'d4('r7)"); \
+ break;
+ S390_SS_A_OPCODE_LIST(DECODE_SS_A_INSTRUCTIONS)
+#undef DECODE_SS_A_INSTRUCTIONS
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+// Disassemble the instruction at *instr_ptr into the output buffer.
+int Decoder::InstructionDecode(byte* instr_ptr) {
+ Instruction* instr = Instruction::At(instr_ptr);
+ int instrLength = instr->InstructionLength();
+
+ // Print the Instruction bits.
+ if (instrLength == 2) {
+ out_buffer_pos_ +=
+ SNPrintF(out_buffer_ + out_buffer_pos_, "%04x ",
+ instr->InstructionBits<TwoByteInstr>());
+ } else if (instrLength == 4) {
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%08x ",
+ instr->InstructionBits<FourByteInstr>());
+ } else {
+ out_buffer_pos_ +=
+ SNPrintF(out_buffer_ + out_buffer_pos_, "%012" PRIx64 " ",
+ instr->InstructionBits<SixByteInstr>());
+ }
+
+ bool decoded = DecodeSpecial(instr);
+ if (!decoded) decoded = DecodeGeneric(instr);
+ if (!decoded) Unknown(instr);
+ return instrLength;
+}
+
+} // namespace internal
+} // namespace v8
+
+//------------------------------------------------------------------------------
+
+namespace disasm {
+
+const char* NameConverter::NameOfAddress(byte* addr) const {
+ v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
+ return tmp_buffer_.begin();
+}
+
+const char* NameConverter::NameOfConstant(byte* addr) const {
+ return NameOfAddress(addr);
+}
+
+const char* NameConverter::NameOfCPURegister(int reg) const {
+ return RegisterName(i::Register::from_code(reg));
+}
+
+const char* NameConverter::NameOfByteCPURegister(int reg) const {
+ UNREACHABLE(); // S390 does not have the concept of a byte register
+}
+
+const char* NameConverter::NameOfXMMRegister(int reg) const {
+ // S390 does not have XMM register
+ // TODO(joransiu): Consider update this for Vector Regs
+ UNREACHABLE();
+}
+
+const char* NameConverter::NameInCode(byte* addr) const {
+ // The default name converter is called for unknown code. So we will not try
+ // to access any memory.
+ return "";
+}
+
+//------------------------------------------------------------------------------
+
+int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
+ byte* instruction) {
+ v8::internal::Decoder d(converter_, buffer);
+ return d.InstructionDecode(instruction);
+}
+
+// The S390 assembler does not currently use constant pools.
+int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
+
+void Disassembler::Disassemble(FILE* f, byte* begin, byte* end,
+ UnimplementedOpcodeAction unimplemented_action) {
+ NameConverter converter;
+ Disassembler d(converter, unimplemented_action);
+ for (byte* pc = begin; pc < end;) {
+ v8::internal::EmbeddedVector<char, 128> buffer;
+ buffer[0] = '\0';
+ byte* prev_pc = pc;
+ pc += d.InstructionDecode(buffer, pc);
+ v8::internal::PrintF(f, "%p %08x %s\n", static_cast<void*>(prev_pc),
+ *reinterpret_cast<int32_t*>(prev_pc), buffer.begin());
+ }
+}
+
+} // namespace disasm
+
+#endif // V8_TARGET_ARCH_S390