1 /* 2 * Copyright (c) 2013, 2018, Oracle and/or its affiliates. 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 it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 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 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.code; 26 27 import java.lang.invoke.MethodHandle; 28 import java.lang.invoke.MethodHandles; 29 import java.util.Arrays; 30 31 import jdk.vm.ci.code.CodeCacheProvider; 32 import jdk.vm.ci.code.CodeUtil; 33 import jdk.vm.ci.code.CodeUtil.DefaultRefMapFormatter; 34 import jdk.vm.ci.code.CodeUtil.RefMapFormatter; 35 import jdk.vm.ci.code.InstalledCode; 36 import jdk.vm.ci.code.Register; 37 import jdk.vm.ci.code.RegisterConfig; 38 import jdk.vm.ci.code.TargetDescription; 39 import jdk.vm.ci.code.site.Call; 40 import jdk.vm.ci.code.site.DataPatch; 41 import jdk.vm.ci.code.site.ExceptionHandler; 42 import jdk.vm.ci.code.site.Infopoint; 43 import jdk.vm.ci.code.site.Mark; 44 45 import org.graalvm.compiler.serviceprovider.ServiceProvider; 46 47 /** 48 * {@link HexCodeFile} based implementation of {@link DisassemblerProvider}. 49 */ 50 @ServiceProvider(DisassemblerProvider.class) 51 public class HexCodeFileDisassemblerProvider implements DisassemblerProvider { 52 53 @Override 54 public String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) { 55 assert compResult != null; 56 return disassemble(codeCache, compResult, null); 57 } 58 59 @Override 60 public String getName() { 61 return "hcf"; 62 } 63 64 @Override 65 public String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) { 66 assert installedCode != null; 67 return installedCode.isValid() ? disassemble(codeCache, compResult, installedCode) : null; 68 } 69 70 private static String disassemble(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) { 71 TargetDescription target = codeCache.getTarget(); 72 RegisterConfig regConfig = codeCache.getRegisterConfig(); 73 byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode(); 74 if (code == null) { 75 // Method was deoptimized/invalidated 76 return ""; 77 } 78 long start = installedCode == null ? 0L : installedCode.getStart(); 79 HexCodeFile hcf = new HexCodeFile(code, start, target.arch.getName(), target.wordSize * 8); 80 if (compResult != null) { 81 HexCodeFile.addAnnotations(hcf, compResult.getAnnotations()); 82 addExceptionHandlersComment(compResult, hcf); 83 Register fp = regConfig.getFrameRegister(); 84 RefMapFormatter slotFormatter = new DefaultRefMapFormatter(target.wordSize, fp, 0); 85 for (Infopoint infopoint : compResult.getInfopoints()) { 86 if (infopoint instanceof Call) { 87 Call call = (Call) infopoint; 88 if (call.debugInfo != null) { 89 hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString()); 90 } 91 addOperandComment(hcf, call.pcOffset, "{" + codeCache.getTargetName(call) + "}"); 92 } else { 93 if (infopoint.debugInfo != null) { 94 hcf.addComment(infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString()); 95 } 96 addOperandComment(hcf, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}"); 97 } 98 } 99 for (DataPatch site : compResult.getDataPatches()) { 100 hcf.addOperandComment(site.pcOffset, "{" + site.reference.toString() + "}"); 101 } 102 for (Mark mark : compResult.getMarks()) { 103 hcf.addComment(mark.pcOffset, codeCache.getMarkName(mark)); 104 } 105 } 106 String hcfEmbeddedString = hcf.toEmbeddedString(); 107 return HexCodeFileDisTool.tryDisassemble(hcfEmbeddedString); 108 } 109 110 private static void addExceptionHandlersComment(CompilationResult compResult, HexCodeFile hcf) { 111 if (!compResult.getExceptionHandlers().isEmpty()) { 112 String nl = HexCodeFile.NEW_LINE; 113 StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl); 114 for (ExceptionHandler e : compResult.getExceptionHandlers()) { 115 buf.append(" ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl); 116 hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]"); 117 hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]"); 118 } 119 hcf.addComment(0, buf.toString()); 120 } 121 } 122 123 private static void addOperandComment(HexCodeFile hcf, int pos, String comment) { 124 hcf.addOperandComment(pos, comment); 125 } 126 127 /** 128 * Interface to the tool for disassembling an {@link HexCodeFile#toEmbeddedString() embedded} 129 * {@link HexCodeFile}. 130 */ 131 static class HexCodeFileDisTool { 132 static final MethodHandle processMethod; 133 134 static { 135 MethodHandle toolMethod = null; 136 try { 137 Class<?> toolClass = Class.forName("com.oracle.max.hcfdis.HexCodeFileDis", true, ClassLoader.getSystemClassLoader()); 138 toolMethod = MethodHandles.lookup().unreflect(toolClass.getDeclaredMethod("processEmbeddedString", String.class)); 139 } catch (Exception e) { 140 // Tool not available on the class path 141 } 142 processMethod = toolMethod; 143 } 144 145 public static String tryDisassemble(String hcfEmbeddedString) { 146 if (processMethod != null) { 147 try { 148 return (String) processMethod.invokeExact(hcfEmbeddedString); 149 } catch (Throwable e) { 150 // If the tool is available, for now let's be noisy when it fails 151 throw new InternalError(e); 152 } 153 } 154 return hcfEmbeddedString; 155 } 156 } 157 158 }