| Index: src/s390/disasm-s390.cc
|
| diff --git a/src/s390/disasm-s390.cc b/src/s390/disasm-s390.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5617fa07e13aa317557b913feeaf5934b6355267
|
| --- /dev/null
|
| +++ b/src/s390/disasm-s390.cc
|
| @@ -0,0 +1,1396 @@
|
| +// 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/disasm.h"
|
| +#include "src/macro-assembler.h"
|
| +#include "src/s390/constants-s390.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 DecodeTwoByte(Instruction* instr);
|
| + bool DecodeFourByte(Instruction* instr);
|
| + bool DecodeSixByte(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(DoubleRegister::from_code(reg).ToString());
|
| +}
|
| +
|
| +// 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(format[0] == 'r');
|
| +
|
| + if (format[1] == '1') { // 'r1: register resides in bit 8-11
|
| + RRInstruction* rrinstr = reinterpret_cast<RRInstruction*>(instr);
|
| + int reg = rrinstr->R1Value();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == '2') { // 'r2: register resides in bit 12-15
|
| + RRInstruction* rrinstr = reinterpret_cast<RRInstruction*>(instr);
|
| + int reg = rrinstr->R2Value();
|
| + // 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
|
| + RSInstruction* rsinstr = reinterpret_cast<RSInstruction*>(instr);
|
| + int reg = rsinstr->B2Value();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == '4') { // 'r4: register resides in bit 20-23
|
| + RSInstruction* rsinstr = reinterpret_cast<RSInstruction*>(instr);
|
| + int reg = rsinstr->B2Value();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == '5') { // 'r5: register resides in bit 24-28
|
| + RREInstruction* rreinstr = reinterpret_cast<RREInstruction*>(instr);
|
| + int reg = rreinstr->R1Value();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == '6') { // 'r6: register resides in bit 29-32
|
| + RREInstruction* rreinstr = reinterpret_cast<RREInstruction*>(instr);
|
| + int reg = rreinstr->R2Value();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == '7') { // 'r6: register resides in bit 32-35
|
| + SSInstruction* ssinstr = reinterpret_cast<SSInstruction*>(instr);
|
| + int reg = ssinstr->B2Value();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + }
|
| +
|
| + UNREACHABLE();
|
| + return -1;
|
| +}
|
| +
|
| +int Decoder::FormatFloatingRegister(Instruction* instr, const char* format) {
|
| + DCHECK(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;
|
| + }
|
| + UNREACHABLE();
|
| + return -1;
|
| +}
|
| +
|
| +// 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;
|
| + }
|
| + case 'm': {
|
| + return FormatMask(instr, format);
|
| + }
|
| + }
|
| + case 'd': { // ds value for offset
|
| + return FormatDisplacement(instr, format);
|
| + }
|
| + default: {
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + UNREACHABLE();
|
| + return -1;
|
| +}
|
| +
|
| +int Decoder::FormatMask(Instruction* instr, const char* format) {
|
| + DCHECK(format[0] == 'm');
|
| + int32_t value = 0;
|
| + if ((format[1] == '1')) { // prints the mask format in bit 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 bit 16 - 19
|
| + value = reinterpret_cast<RXInstruction*>(instr)->B2Value();
|
| + 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(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(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();
|
| + return -1;
|
| +}
|
| +
|
| +// 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 ressemble 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);
|
| +}
|
| +
|
| +// Disassembles Two Byte S390 Instructions
|
| +// @return true if successfully decoded
|
| +bool Decoder::DecodeTwoByte(Instruction* instr) {
|
| + // Print the Instruction bits.
|
| + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%04x ",
|
| + instr->InstructionBits<TwoByteInstr>());
|
| +
|
| + Opcode opcode = instr->S390OpcodeValue();
|
| + switch (opcode) {
|
| + case AR:
|
| + Format(instr, "ar\t'r1,'r2");
|
| + break;
|
| + case SR:
|
| + Format(instr, "sr\t'r1,'r2");
|
| + break;
|
| + case MR:
|
| + Format(instr, "mr\t'r1,'r2");
|
| + break;
|
| + case DR:
|
| + Format(instr, "dr\t'r1,'r2");
|
| + break;
|
| + case OR:
|
| + Format(instr, "or\t'r1,'r2");
|
| + break;
|
| + case NR:
|
| + Format(instr, "nr\t'r1,'r2");
|
| + break;
|
| + case XR:
|
| + Format(instr, "xr\t'r1,'r2");
|
| + break;
|
| + case LR:
|
| + Format(instr, "lr\t'r1,'r2");
|
| + break;
|
| + case CR:
|
| + Format(instr, "cr\t'r1,'r2");
|
| + break;
|
| + case CLR:
|
| + Format(instr, "clr\t'r1,'r2");
|
| + break;
|
| + case BCR:
|
| + Format(instr, "bcr\t'm1,'r2");
|
| + break;
|
| + case LTR:
|
| + Format(instr, "ltr\t'r1,'r2");
|
| + break;
|
| + case ALR:
|
| + Format(instr, "alr\t'r1,'r2");
|
| + break;
|
| + case SLR:
|
| + Format(instr, "slr\t'r1,'r2");
|
| + break;
|
| + case LNR:
|
| + Format(instr, "lnr\t'r1,'r2");
|
| + break;
|
| + case LCR:
|
| + Format(instr, "lcr\t'r1,'r2");
|
| + break;
|
| + case BASR:
|
| + Format(instr, "basr\t'r1,'r2");
|
| + break;
|
| + case LDR:
|
| + Format(instr, "ldr\t'f1,'f2");
|
| + break;
|
| + case BKPT:
|
| + Format(instr, "bkpt");
|
| + break;
|
| + default:
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +// Disassembles Four Byte S390 Instructions
|
| +// @return true if successfully decoded
|
| +bool Decoder::DecodeFourByte(Instruction* instr) {
|
| + // Print the Instruction bits.
|
| + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%08x ",
|
| + instr->InstructionBits<FourByteInstr>());
|
| +
|
| + Opcode opcode = instr->S390OpcodeValue();
|
| + switch (opcode) {
|
| + case AHI:
|
| + Format(instr, "ahi\t'r1,'i1");
|
| + break;
|
| + case AGHI:
|
| + Format(instr, "aghi\t'r1,'i1");
|
| + break;
|
| + case LHI:
|
| + Format(instr, "lhi\t'r1,'i1");
|
| + break;
|
| + case LGHI:
|
| + Format(instr, "lghi\t'r1,'i1");
|
| + break;
|
| + case MHI:
|
| + Format(instr, "mhi\t'r1,'i1");
|
| + break;
|
| + case MGHI:
|
| + Format(instr, "mghi\t'r1,'i1");
|
| + break;
|
| + case CHI:
|
| + Format(instr, "chi\t'r1,'i1");
|
| + break;
|
| + case CGHI:
|
| + Format(instr, "cghi\t'r1,'i1");
|
| + break;
|
| + case BRAS:
|
| + Format(instr, "bras\t'r1,'i1");
|
| + break;
|
| + case BRC:
|
| + Format(instr, "brc\t'm1,'i4");
|
| + break;
|
| + case BRCT:
|
| + Format(instr, "brct\t'r1,'i4");
|
| + break;
|
| + case BRCTG:
|
| + Format(instr, "brctg\t'r1,'i4");
|
| + break;
|
| + case IIHH:
|
| + Format(instr, "iihh\t'r1,'i1");
|
| + break;
|
| + case IIHL:
|
| + Format(instr, "iihl\t'r1,'i1");
|
| + break;
|
| + case IILH:
|
| + Format(instr, "iilh\t'r1,'i1");
|
| + break;
|
| + case IILL:
|
| + Format(instr, "iill\t'r1,'i1");
|
| + break;
|
| + case OILL:
|
| + Format(instr, "oill\t'r1,'i1");
|
| + break;
|
| + case TMLL:
|
| + Format(instr, "tmll\t'r1,'i1");
|
| + break;
|
| + case STM:
|
| + Format(instr, "stm\t'r1,'r2,'d1('r3)");
|
| + break;
|
| + case LM:
|
| + Format(instr, "lm\t'r1,'r2,'d1('r3)");
|
| + break;
|
| + case SLL:
|
| + Format(instr, "sll\t'r1,'d1('r3)");
|
| + break;
|
| + case SRL:
|
| + Format(instr, "srl\t'r1,'d1('r3)");
|
| + break;
|
| + case SLA:
|
| + Format(instr, "sla\t'r1,'d1('r3)");
|
| + break;
|
| + case SRA:
|
| + Format(instr, "sra\t'r1,'d1('r3)");
|
| + break;
|
| + case AGR:
|
| + Format(instr, "agr\t'r5,'r6");
|
| + break;
|
| + case AGFR:
|
| + Format(instr, "agfr\t'r5,'r6");
|
| + break;
|
| + case ARK:
|
| + Format(instr, "ark\t'r5,'r6,'r3");
|
| + break;
|
| + case AGRK:
|
| + Format(instr, "agrk\t'r5,'r6,'r3");
|
| + break;
|
| + case SGR:
|
| + Format(instr, "sgr\t'r5,'r6");
|
| + break;
|
| + case SGFR:
|
| + Format(instr, "sgfr\t'r5,'r6");
|
| + break;
|
| + case SRK:
|
| + Format(instr, "srk\t'r5,'r6,'r3");
|
| + break;
|
| + case SGRK:
|
| + Format(instr, "sgrk\t'r5,'r6,'r3");
|
| + break;
|
| + case NGR:
|
| + Format(instr, "ngr\t'r5,'r6");
|
| + break;
|
| + case NRK:
|
| + Format(instr, "nrk\t'r5,'r6,'r3");
|
| + break;
|
| + case NGRK:
|
| + Format(instr, "ngrk\t'r5,'r6,'r3");
|
| + break;
|
| + case NILL:
|
| + Format(instr, "nill\t'r1,'i1");
|
| + break;
|
| + case NILH:
|
| + Format(instr, "nilh\t'r1,'i1");
|
| + break;
|
| + case OGR:
|
| + Format(instr, "ogr\t'r5,'r6");
|
| + break;
|
| + case ORK:
|
| + Format(instr, "ork\t'r5,'r6,'r3");
|
| + break;
|
| + case OGRK:
|
| + Format(instr, "ogrk\t'r5,'r6,'r3");
|
| + break;
|
| + case XGR:
|
| + Format(instr, "xgr\t'r5,'r6");
|
| + break;
|
| + case XRK:
|
| + Format(instr, "xrk\t'r5,'r6,'r3");
|
| + break;
|
| + case XGRK:
|
| + Format(instr, "xgrk\t'r5,'r6,'r3");
|
| + break;
|
| + case CGR:
|
| + Format(instr, "cgr\t'r5,'r6");
|
| + break;
|
| + case CLGR:
|
| + Format(instr, "clgr\t'r5,'r6");
|
| + break;
|
| + case LLGFR:
|
| + Format(instr, "llgfr\t'r5,'r6");
|
| + break;
|
| + case LBR:
|
| + Format(instr, "lbr\t'r5,'r6");
|
| + break;
|
| + case LEDBR:
|
| + Format(instr, "ledbr\t'f5,'f6");
|
| + break;
|
| + case LDEBR:
|
| + Format(instr, "ldebr\t'f5,'f6");
|
| + break;
|
| + case LTGR:
|
| + Format(instr, "ltgr\t'r5,'r6");
|
| + break;
|
| + case LTDBR:
|
| + Format(instr, "ltdbr\t'f5,'f6");
|
| + break;
|
| + case LTEBR:
|
| + Format(instr, "ltebr\t'f5,'f6");
|
| + break;
|
| + case LGR:
|
| + Format(instr, "lgr\t'r5,'r6");
|
| + break;
|
| + case LGDR:
|
| + Format(instr, "lgdr\t'r5,'f6");
|
| + break;
|
| + case LGFR:
|
| + Format(instr, "lgfr\t'r5,'r6");
|
| + break;
|
| + case LTGFR:
|
| + Format(instr, "ltgfr\t'r5,'r6");
|
| + break;
|
| + case LCGR:
|
| + Format(instr, "lcgr\t'r5,'r6");
|
| + break;
|
| + case MSR:
|
| + Format(instr, "msr\t'r5,'r6");
|
| + break;
|
| + case LGBR:
|
| + Format(instr, "lgbr\t'r5,'r6");
|
| + break;
|
| + case LGHR:
|
| + Format(instr, "lghr\t'r5,'r6");
|
| + break;
|
| + case MSGR:
|
| + Format(instr, "msgr\t'r5,'r6");
|
| + break;
|
| + case DSGR:
|
| + Format(instr, "dsgr\t'r5,'r6");
|
| + break;
|
| + case LZDR:
|
| + Format(instr, "lzdr\t'f5");
|
| + break;
|
| + case MLR:
|
| + Format(instr, "mlr\t'r5,'r6");
|
| + break;
|
| + case MLGR:
|
| + Format(instr, "mlgr\t'r5,'r6");
|
| + break;
|
| + case ALGR:
|
| + Format(instr, "algr\t'r5,'r6");
|
| + break;
|
| + case ALRK:
|
| + Format(instr, "alrk\t'r5,'r6,'r3");
|
| + break;
|
| + case ALGRK:
|
| + Format(instr, "algrk\t'r5,'r6,'r3");
|
| + break;
|
| + case SLGR:
|
| + Format(instr, "slgr\t'r5,'r6");
|
| + break;
|
| + case DLR:
|
| + Format(instr, "dlr\t'r1,'r2");
|
| + break;
|
| + case DLGR:
|
| + Format(instr, "dlgr\t'r5,'r6");
|
| + break;
|
| + case SLRK:
|
| + Format(instr, "slrk\t'r5,'r6,'r3");
|
| + break;
|
| + case SLGRK:
|
| + Format(instr, "slgrk\t'r5,'r6,'r3");
|
| + break;
|
| + case LHR:
|
| + Format(instr, "lhr\t'r5,'r6");
|
| + break;
|
| + case LLHR:
|
| + Format(instr, "llhr\t'r5,'r6");
|
| + break;
|
| + case LLGHR:
|
| + Format(instr, "llghr\t'r5,'r6");
|
| + break;
|
| + case LNGR:
|
| + Format(instr, "lngr\t'r5,'r6");
|
| + break;
|
| + case A:
|
| + Format(instr, "a\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case S:
|
| + Format(instr, "s\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case M:
|
| + Format(instr, "m\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case D:
|
| + Format(instr, "d\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case O:
|
| + Format(instr, "o\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case N:
|
| + Format(instr, "n\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case L:
|
| + Format(instr, "l\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case C:
|
| + Format(instr, "c\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case AH:
|
| + Format(instr, "ah\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case SH:
|
| + Format(instr, "sh\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case MH:
|
| + Format(instr, "mh\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case AL:
|
| + Format(instr, "al\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case SL:
|
| + Format(instr, "sl\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case LA:
|
| + Format(instr, "la\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case CH:
|
| + Format(instr, "ch\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case CL:
|
| + Format(instr, "cl\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case CLI:
|
| + Format(instr, "cli\t'd1('r3),'i8");
|
| + break;
|
| + case TM:
|
| + Format(instr, "tm\t'd1('r3),'i8");
|
| + break;
|
| + case BC:
|
| + Format(instr, "bc\t'm1,'d1('r2d,'r3)");
|
| + break;
|
| + case BCT:
|
| + Format(instr, "bct\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case ST:
|
| + Format(instr, "st\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case STC:
|
| + Format(instr, "stc\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case IC_z:
|
| + Format(instr, "ic\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case LD:
|
| + Format(instr, "ld\t'f1,'d1('r2d,'r3)");
|
| + break;
|
| + case LE:
|
| + Format(instr, "le\t'f1,'d1('r2d,'r3)");
|
| + break;
|
| + case LDGR:
|
| + Format(instr, "ldgr\t'f5,'r6");
|
| + break;
|
| + case STE:
|
| + Format(instr, "ste\t'f1,'d1('r2d,'r3)");
|
| + break;
|
| + case STD:
|
| + Format(instr, "std\t'f1,'d1('r2d,'r3)");
|
| + break;
|
| + case CFDBR:
|
| + Format(instr, "cfdbr\t'r5,'m2,'f6");
|
| + break;
|
| + case CDFBR:
|
| + Format(instr, "cdfbr\t'f5,'m2,'r6");
|
| + break;
|
| + case CFEBR:
|
| + Format(instr, "cfebr\t'r5,'m2,'f6");
|
| + break;
|
| + case CEFBR:
|
| + Format(instr, "cefbr\t'f5,'m2,'r6");
|
| + break;
|
| + case CGEBR:
|
| + Format(instr, "cgebr\t'r5,'m2,'f6");
|
| + break;
|
| + case CGDBR:
|
| + Format(instr, "cgdbr\t'r5,'m2,'f6");
|
| + break;
|
| + case CEGBR:
|
| + Format(instr, "cegbr\t'f5,'m2,'r6");
|
| + break;
|
| + case CDGBR:
|
| + Format(instr, "cdgbr\t'f5,'m2,'r6");
|
| + break;
|
| + case CDLFBR:
|
| + Format(instr, "cdlfbr\t'f5,'m2,'r6");
|
| + break;
|
| + case CDLGBR:
|
| + Format(instr, "cdlgbr\t'f5,'m2,'r6");
|
| + break;
|
| + case CELGBR:
|
| + Format(instr, "celgbr\t'f5,'m2,'r6");
|
| + break;
|
| + case CLFDBR:
|
| + Format(instr, "clfdbr\t'r5,'m2,'f6");
|
| + break;
|
| + case CLGDBR:
|
| + Format(instr, "clgdbr\t'r5,'m2,'f6");
|
| + break;
|
| + case AEBR:
|
| + Format(instr, "aebr\t'f5,'f6");
|
| + break;
|
| + case SEBR:
|
| + Format(instr, "sebr\t'f5,'f6");
|
| + break;
|
| + case MEEBR:
|
| + Format(instr, "meebr\t'f5,'f6");
|
| + break;
|
| + case DEBR:
|
| + Format(instr, "debr\t'f5,'f6");
|
| + break;
|
| + case ADBR:
|
| + Format(instr, "adbr\t'f5,'f6");
|
| + break;
|
| + case SDBR:
|
| + Format(instr, "sdbr\t'f5,'f6");
|
| + break;
|
| + case MDBR:
|
| + Format(instr, "mdbr\t'f5,'f6");
|
| + break;
|
| + case DDBR:
|
| + Format(instr, "ddbr\t'f5,'f6");
|
| + break;
|
| + case CDBR:
|
| + Format(instr, "cdbr\t'f5,'f6");
|
| + break;
|
| + case SQDBR:
|
| + Format(instr, "sqdbr\t'f5,'f6");
|
| + break;
|
| + case LCDBR:
|
| + Format(instr, "lcdbr\t'f5,'f6");
|
| + break;
|
| + case STH:
|
| + Format(instr, "sth\t'r1,'d1('r2d,'r3)");
|
| + break;
|
| + case SRDA:
|
| + Format(instr, "srda\t'r1,'d1");
|
| + break;
|
| + case SRDL:
|
| + Format(instr, "srdl\t'r1,'d1");
|
| + break;
|
| + case MADBR:
|
| + Format(instr, "madbr\t'f3,'f5,'f6");
|
| + break;
|
| + case MSDBR:
|
| + Format(instr, "msdbr\t'f3,'f5,'f6");
|
| + break;
|
| + case FLOGR:
|
| + Format(instr, "flogr\t'r5,'r6");
|
| + break;
|
| + // TRAP4 is used in calling to native function. it will not be generated
|
| + // in native code.
|
| + case TRAP4: {
|
| + Format(instr, "trap4");
|
| + break;
|
| + }
|
| + default:
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +// Disassembles Six Byte S390 Instructions
|
| +// @return true if successfully decoded
|
| +bool Decoder::DecodeSixByte(Instruction* instr) {
|
| + // Print the Instruction bits.
|
| + out_buffer_pos_ +=
|
| + SNPrintF(out_buffer_ + out_buffer_pos_, "%012" PRIx64 " ",
|
| + instr->InstructionBits<SixByteInstr>());
|
| +
|
| + Opcode opcode = instr->S390OpcodeValue();
|
| + switch (opcode) {
|
| + case LLILF:
|
| + Format(instr, "llilf\t'r1,'i7");
|
| + break;
|
| + case LLIHF:
|
| + Format(instr, "llihf\t'r1,'i7");
|
| + break;
|
| + case AFI:
|
| + Format(instr, "afi\t'r1,'i7");
|
| + break;
|
| + case ASI:
|
| + Format(instr, "asi\t'd2('r3),'ic");
|
| + break;
|
| + case AGSI:
|
| + Format(instr, "agsi\t'd2('r3),'ic");
|
| + break;
|
| + case ALFI:
|
| + Format(instr, "alfi\t'r1,'i7");
|
| + break;
|
| + case AHIK:
|
| + Format(instr, "ahik\t'r1,'r2,'i1");
|
| + break;
|
| + case AGHIK:
|
| + Format(instr, "aghik\t'r1,'r2,'i1");
|
| + break;
|
| + case CLGFI:
|
| + Format(instr, "clgfi\t'r1,'i7");
|
| + break;
|
| + case CLFI:
|
| + Format(instr, "clfi\t'r1,'i7");
|
| + break;
|
| + case CFI:
|
| + Format(instr, "cfi\t'r1,'i2");
|
| + break;
|
| + case CGFI:
|
| + Format(instr, "cgfi\t'r1,'i2");
|
| + break;
|
| + case BRASL:
|
| + Format(instr, "brasl\t'r1,'ie");
|
| + break;
|
| + case BRCL:
|
| + Format(instr, "brcl\t'm1,'i5");
|
| + break;
|
| + case IIHF:
|
| + Format(instr, "iihf\t'r1,'i7");
|
| + break;
|
| + case IILF:
|
| + Format(instr, "iilf\t'r1,'i7");
|
| + break;
|
| + case XIHF:
|
| + Format(instr, "xihf\t'r1,'i7");
|
| + break;
|
| + case XILF:
|
| + Format(instr, "xilf\t'r1,'i7");
|
| + break;
|
| + case SLLK:
|
| + Format(instr, "sllk\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case SLLG:
|
| + Format(instr, "sllg\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case RLL:
|
| + Format(instr, "rll\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case RLLG:
|
| + Format(instr, "rllg\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case SRLK:
|
| + Format(instr, "srlk\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case SRLG:
|
| + Format(instr, "srlg\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case SLAK:
|
| + Format(instr, "slak\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case SLAG:
|
| + Format(instr, "slag\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case SRAK:
|
| + Format(instr, "srak\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case SRAG:
|
| + Format(instr, "srag\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case RISBG:
|
| + Format(instr, "risbg\t'r1,'r2,'i9,'ia,'ib");
|
| + break;
|
| + case RISBGN:
|
| + Format(instr, "risbgn\t'r1,'r2,'i9,'ia,'ib");
|
| + break;
|
| + case LMY:
|
| + Format(instr, "lmy\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case LMG:
|
| + Format(instr, "lmg\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case STMY:
|
| + Format(instr, "stmy\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case STMG:
|
| + Format(instr, "stmg\t'r1,'r2,'d2('r3)");
|
| + break;
|
| + case LT:
|
| + Format(instr, "lt\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LTG:
|
| + Format(instr, "ltg\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case ML:
|
| + Format(instr, "ml\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case AY:
|
| + Format(instr, "ay\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case SY:
|
| + Format(instr, "sy\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case NY:
|
| + Format(instr, "ny\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case OY:
|
| + Format(instr, "oy\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case XY:
|
| + Format(instr, "xy\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case CY:
|
| + Format(instr, "cy\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case AHY:
|
| + Format(instr, "ahy\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case SHY:
|
| + Format(instr, "shy\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LGH:
|
| + Format(instr, "lgh\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case AG:
|
| + Format(instr, "ag\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case AGF:
|
| + Format(instr, "agf\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case SG:
|
| + Format(instr, "sg\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case NG:
|
| + Format(instr, "ng\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case OG:
|
| + Format(instr, "og\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case XG:
|
| + Format(instr, "xg\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case CG:
|
| + Format(instr, "cg\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LB:
|
| + Format(instr, "lb\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LG:
|
| + Format(instr, "lg\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LGF:
|
| + Format(instr, "lgf\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LLGF:
|
| + Format(instr, "llgf\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LY:
|
| + Format(instr, "ly\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case ALY:
|
| + Format(instr, "aly\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case ALG:
|
| + Format(instr, "alg\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case SLG:
|
| + Format(instr, "slg\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case SGF:
|
| + Format(instr, "sgf\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case SLY:
|
| + Format(instr, "sly\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LLH:
|
| + Format(instr, "llh\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LLGH:
|
| + Format(instr, "llgh\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LLC:
|
| + Format(instr, "llc\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LLGC:
|
| + Format(instr, "llgc\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LDEB:
|
| + Format(instr, "ldeb\t'f1,'d2('r2d,'r3)");
|
| + break;
|
| + case LAY:
|
| + Format(instr, "lay\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case LARL:
|
| + Format(instr, "larl\t'r1,'i5");
|
| + break;
|
| + case LGB:
|
| + Format(instr, "lgb\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case CHY:
|
| + Format(instr, "chy\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case CLY:
|
| + Format(instr, "cly\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case CLIY:
|
| + Format(instr, "cliy\t'd2('r3),'i8");
|
| + break;
|
| + case TMY:
|
| + Format(instr, "tmy\t'd2('r3),'i8");
|
| + break;
|
| + case CLG:
|
| + Format(instr, "clg\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case BCTG:
|
| + Format(instr, "bctg\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case STY:
|
| + Format(instr, "sty\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case STG:
|
| + Format(instr, "stg\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case ICY:
|
| + Format(instr, "icy\t'r1,'d2('r2d,'r3)");
|
| + break;
|
| + case MVC:
|
| + Format(instr, "mvc\t'd3('i8,'r3),'d4('r7)");
|
| + break;
|
| + case MVHI:
|
| + Format(instr, "mvhi\t'd3('r3),'id");
|
| + break;
|
| + case MVGHI:
|
| + Format(instr, "mvghi\t'd3('r3),'id");
|
| + break;
|
| + case ALGFI:
|
| + Format(instr, "algfi\t'r1,'i7");
|
| + break;
|
| + case SLGFI:
|
| + Format(instr, "slgfi\t'r1,'i7");
|
| + break;
|
| + case SLFI:
|
| + Format(instr, "slfi\t'r1,'i7");
|
| + break;
|
| + case NIHF:
|
| + Format(instr, "nihf\t'r1,'i7");
|
| + break;
|
| + case NILF:
|
| + Format(instr, "nilf\t'r1,'i7");
|
| + break;
|
| + case OIHF:
|
| + Format(instr, "oihf\t'r1,'i7");
|
| + break;
|
| + case OILF:
|
| + Format(instr, "oilf\t'r1,'i7");
|
| + break;
|
| + case MSFI:
|
| + Format(instr, "msfi\t'r1,'i7");
|
| + break;
|
| + case MSGFI:
|
| + Format(instr, "msgfi\t'r1,'i7");
|
| + break;
|
| + case LDY:
|
| + Format(instr, "ldy\t'f1,'d2('r2d,'r3)");
|
| + break;
|
| + case LEY:
|
| + Format(instr, "ley\t'f1,'d2('r2d,'r3)");
|
| + break;
|
| + case STEY:
|
| + Format(instr, "stey\t'f1,'d2('r2d,'r3)");
|
| + break;
|
| + case STDY:
|
| + Format(instr, "stdy\t'f1,'d2('r2d,'r3)");
|
| + break;
|
| + case ADB:
|
| + Format(instr, "adb\t'r1,'d1('r2d, 'r3)");
|
| + break;
|
| + case SDB:
|
| + Format(instr, "sdb\t'r1,'d1('r2d, 'r3)");
|
| + break;
|
| + case MDB:
|
| + Format(instr, "mdb\t'r1,'d1('r2d, 'r3)");
|
| + break;
|
| + case DDB:
|
| + Format(instr, "ddb\t'r1,'d1('r2d, 'r3)");
|
| + break;
|
| + case SQDB:
|
| + Format(instr, "sqdb\t'r1,'d1('r2d, 'r3)");
|
| + break;
|
| + default:
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +#undef VERIFIY
|
| +
|
| +// 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();
|
| +
|
| + if (2 == instrLength)
|
| + DecodeTwoByte(instr);
|
| + else if (4 == instrLength)
|
| + DecodeFourByte(instr);
|
| + else
|
| + DecodeSixByte(instr);
|
| +
|
| + return instrLength;
|
| +}
|
| +
|
| +} // namespace internal
|
| +} // namespace v8
|
| +
|
| +//------------------------------------------------------------------------------
|
| +
|
| +namespace disasm {
|
| +
|
| +const char* NameConverter::NameOfAddress(byte* addr) const {
|
| + v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
|
| + return tmp_buffer_.start();
|
| +}
|
| +
|
| +const char* NameConverter::NameOfConstant(byte* addr) const {
|
| + return NameOfAddress(addr);
|
| +}
|
| +
|
| +const char* NameConverter::NameOfCPURegister(int reg) const {
|
| + return v8::internal::Register::from_code(reg).ToString();
|
| +}
|
| +
|
| +const char* NameConverter::NameOfByteCPURegister(int reg) const {
|
| + UNREACHABLE(); // S390 does not have the concept of a byte register
|
| + return "nobytereg";
|
| +}
|
| +
|
| +const char* NameConverter::NameOfXMMRegister(int reg) const {
|
| + // S390 does not have XMM register
|
| + // TODO(joransiu): Consider update this for Vector Regs
|
| + UNREACHABLE();
|
| + return "noxmmreg";
|
| +}
|
| +
|
| +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 "";
|
| +}
|
| +
|
| +//------------------------------------------------------------------------------
|
| +
|
| +Disassembler::Disassembler(const NameConverter& converter)
|
| + : converter_(converter) {}
|
| +
|
| +Disassembler::~Disassembler() {}
|
| +
|
| +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) {
|
| + NameConverter converter;
|
| + Disassembler d(converter);
|
| + 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", prev_pc,
|
| + *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
|
| + }
|
| +}
|
| +
|
| +} // namespace disasm
|
| +
|
| +#endif // V8_TARGET_ARCH_S390
|
|
|