Path: blob/master/src/hotspot/cpu/s390/disassembler_s390.cpp
40930 views
/*1* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2019 SAP SE. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "asm/assembler.inline.hpp"26#include "asm/macroAssembler.hpp"27#include "code/codeCache.hpp"28#include "compiler/disassembler.hpp"29#include "gc/shared/collectedHeap.hpp"30#include "gc/shared/cardTableBarrierSet.hpp"31#include "gc/shared/genOopClosures.inline.hpp"32#include "oops/oop.inline.hpp"33#include "runtime/handles.inline.hpp"34#include "runtime/stubCodeGenerator.hpp"35#include "runtime/stubRoutines.hpp"36#include "utilities/align.hpp"3738// List of all major opcodes, as of39// Principles of Operation, Eleventh Edition, March 201540bool Disassembler::valid_opcodes[] =41{ true, true, false, false, true, true, true, true, // 0x00..0742false, false, true, true, true, true, true, true, // 0x08..0f43true, true, true, true, true, true, true, true, // 0x10..1744true, true, true, true, true, true, true, true, // 0x18..1f45true, true, true, true, true, true, true, true, // 0x20..2746true, true, true, true, true, true, true, true, // 0x28..2f47true, true, true, true, true, true, true, true, // 0x30..3748true, true, true, true, true, true, true, true, // 0x38..3f49true, true, true, true, true, true, true, true, // 0x40..4750true, true, true, true, true, true, true, true, // 0x48..4f51true, true, false, false, true, true, true, true, // 0x50..5752true, true, true, true, true, true, true, true, // 0x58..5f53true, false, false, false, false, false, false, true, // 0x60..6754true, true, true, true, true, true, true, true, // 0x68..6f55true, true, false, false, false, false, false, false, // 0x70..7756true, true, true, true, true, true, true, true, // 0x78..7f57true, false, true, true, true, true, true, true, // 0x80..8758true, true, true, true, true, true, true, true, // 0x88..8f59true, true, true, true, true, true, true, true, // 0x90..9760true, true, true, true, false, false, false, false, // 0x98..9f61false, false, false, false, false, true, false, true, // 0xa0..a762true, true, false, false, true, true, true, true, // 0xa8..af63false, true, true, true, false, false, true, true, // 0xb0..b764false, true, true, true, false, true, true, true, // 0xb8..bf65true, false, true, false, true, false, true, false, // 0xc0..c766true, false, false, false, true, false, false, false, // 0xc8..cf67true, true, true, true, true, true, true, true, // 0xd0..d768false, true, true, true, true, true, true, true, // 0xd8..df69false, true, true, true, false, true, false, true, // 0xe0..e770true, true, true, true, true, true, true, true, // 0xe8..ef71true, true, true, true, false, false, false, false, // 0xf0..f772true, true, true, true, true, true, false, false, // 0xf8..ff73};74// Check for valid opcodes.75//76// The major opcode (one byte) at the passed location is inspected.77// If the opcode found is assigned, the function returns true, false otherwise.78// The true indication is not reliable. It may well be that the major opcode is79// assigned, but there exists a minor opcode field in the instruction which80// which has unassigned values.81bool Disassembler::is_valid_opcode_at(address here) {82return valid_opcodes[*here];83}8485// This method does plain instruction decoding, no frills.86// It may be called before the binutils disassembler kicks in87// to handle special cases the binutils disassembler does not.88// Instruction address, comments, and the like have to be output by caller.89address Disassembler::decode_instruction0(address here, outputStream * st, address virtual_begin) {90if (is_abstract()) {91// The disassembler library was not loaded (yet),92// use AbstractDisassembler's decode-method.93return decode_instruction_abstract(here, st, Assembler::instr_len(here), Assembler::instr_maxlen());94}9596// Currently, "special decoding" doesn't work when decoding error files.97// When decoding an instruction from a hs_err file, the given98// instruction address 'start' points to the instruction's virtual address99// which is not equal to the address where the instruction is located.100// Therefore, we will either crash or decode garbage.101if (is_decode_error_file()) {102return here;103}104105//---< Decode some well-known "instructions" >---106107address next;108uint16_t instruction_2bytes = *(uint16_t*)here;109110if (Assembler::is_z_nop((long)instruction_2bytes)) {111#if 1112st->print("nop "); // fill up to operand column, leads to better code comment alignment113next = here + 2;114#else115// Compact disassembler output. Does not work the easy way.116// Currently unusable, search does not terminate, risk of crash.117// TODO: rework required.118// Terminate search loop when reaching CodeEntryAlignment-aligned offset119// or, at the latest, when reaching the next page boundary.120int n_nops = 0;121while(is_same_page(here, here+2*n_nops) && Assembler::is_z_nop((long)instruction_2bytes)) {122n_nops++;123instruction_2bytes = *(uint16_t*)(here+2*n_nops);124}125if (n_nops <= 4) { // do not group few subsequent nops126st->print("nop "); // fill up to operand column, leads to better code comment alignment127next = here + 2;128} else {129st->print("nop count=%d", n_nops);130next = here + 2*n_nops;131}132#endif133} else if (Assembler::is_z_sync((long)instruction_2bytes)) {134// Specific names. Make use of lightweight sync.135st->print("sync ");136if (Assembler::is_z_sync_full((long)instruction_2bytes) ) st->print("heavyweight");137if (Assembler::is_z_sync_light((long)instruction_2bytes)) st->print("lightweight");138next = here + 2;139} else if (instruction_2bytes == 0x0000) {140#if 1141st->print("illtrap .nodata");142next = here + 2;143#else144// Compact disassembler output. Does not work the easy way.145// Currently unusable, search does not terminate, risk of crash.146// TODO: rework required.147// Terminate search loop when reaching CodeEntryAlignment-aligned offset148// or, at the latest, when reaching the next page boundary.149int n_traps = 0;150while(is_same_page(here, here+2*n_nops) && (instruction_2bytes == 0x0000)) {151n_traps++;152instruction_2bytes = *(uint16_t*)(here+2*n_traps);153}154if (n_traps <= 4) { // do not group few subsequent illtraps155st->print("illtrap .nodata");156next = here + 2;157} else {158st->print("illtrap .nodata count=%d", n_traps);159next = here + 2*n_traps;160}161#endif162} else if ((instruction_2bytes & 0xff00) == 0x0000) {163st->print("illtrap .data 0x%2.2x", instruction_2bytes & 0x00ff);164next = here + 2;165} else {166next = here;167}168return next;169}170171// Count the instructions contained in the range [begin..end).172// The range must exactly contain the instructions, i.e.173// - the first instruction starts @begin174// - the last instruction ends @(end-1)175// The caller has to make sure that the given range is readable.176// This function performs no safety checks!177// Return value:178// - The number of instructions, if there was exact containment.179// - If there is no exact containment, a negative value is returned.180// Its absolute value is the number of instructions from begin to end,181// where the last instruction counted runs over the range end.182// - 0 (zero) is returned if there was a parameter error183// (inverted range, bad starting point).184int Disassembler::count_instr(address begin, address end) {185if (end < begin+2) return 0; // no instructions in range186if (!Disassembler::is_valid_opcode_at(begin)) return 0; // bad starting point187188address p = begin;189int n = 0;190while(p < end) {191p += Assembler::instr_len(p);192n++;193}194return (p == end) ? n : -n;195}196197// Find preceding instruction.198//199// Starting at the passed location, the n-th preceding (towards lower addresses)200// instruction is searched. With variable length instructions, there may be201// more than one solution, or no solution at all (if the passed location202// does not point to the start of an instruction or if the storage area203// does not contain instructions at all).204// instructions - has the passed location as n-th successor.205// - If multiple such locations exist between (here-n*instr_maxlen()) and here,206// the most distant location is selected.207// - If no such location exists, NULL is returned. The caller should then208// terminate its search and react properly.209// Must be placed here in disassembler_s390.cpp. It does not compile210// in the header. There the class 'Assembler' is not available.211address Disassembler::find_prev_instr(address here, int n_instr) {212if (!os::is_readable_pointer(here)) return NULL; // obviously a bad location to decode213214// Find most distant possible starting point.215// Narrow down because we don't want to SEGV while printing.216address start = here - n_instr*Assembler::instr_maxlen(); // starting point can't be further away.217while ((start < here) && !os::is_readable_range(start, here)) {218start = align_down(start, os::min_page_size()) + os::min_page_size();219}220if (start >= here) {221// Strange. Can only happen with here on page boundary.222return NULL;223}224225//---< Find a starting point >---226int i_count = 0;227while ((start < here) && ((i_count = count_instr(start, here)) <= 0)) start += 2;228if (i_count == 0) return NULL; // There is something seriously wrong229230//---< Narrow down distance (estimate was too large) >---231while(i_count-- > n_instr) {232start += Assembler::instr_len(start);233}234assert(n_instr >= count_instr(start, here), "just checking");235return start;236}237238239// Print annotations (value of loaded constant)240void Disassembler::annotate(address here, outputStream* st) {241// Currently, annotation doesn't work when decoding error files.242// When decoding an instruction from a hs_err file, the given243// instruction address 'start' points to the instruction's virtual address244// which is not equal to the address where the instruction is located.245// Therefore, we will either crash or decode garbage.246if (is_decode_error_file()) {247return;248}249250if (MacroAssembler::is_load_const(here)) {251long value = MacroAssembler::get_const(here);252const int tsize = 8;253254st->fill_to(60);255st->print(";const %p | %ld | %23.15e", (void *)value, value, (double)value);256}257}258259260