Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2016 Justin Shapcott.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.robovm.compiler.plugin.debug;
import org.robovm.compiler.Annotations;
import org.robovm.compiler.Functions;
import org.robovm.compiler.ModuleBuilder;
import org.robovm.compiler.Symbols;
import org.robovm.compiler.clazz.Clazz;
import org.robovm.compiler.config.Config;
import org.robovm.compiler.config.OS;
import org.robovm.compiler.llvm.Alloca;
import org.robovm.compiler.llvm.ArrayConstantBuilder;
import org.robovm.compiler.llvm.BasicBlock;
import org.robovm.compiler.llvm.Call;
import org.robovm.compiler.llvm.Constant;
import org.robovm.compiler.llvm.ConstantBitcast;
import org.robovm.compiler.llvm.Function;
import org.robovm.compiler.llvm.FunctionDeclaration;
import org.robovm.compiler.llvm.Global;
import org.robovm.compiler.llvm.Instruction;
import org.robovm.compiler.llvm.IntegerConstant;
import org.robovm.compiler.llvm.MetadataString;
import org.robovm.compiler.llvm.MetadataValue;
import org.robovm.compiler.llvm.PointerType;
import org.robovm.compiler.llvm.Type;
import org.robovm.compiler.llvm.Value;
import org.robovm.compiler.llvm.Variable;
import org.robovm.compiler.llvm.VariableRef;
import org.robovm.compiler.llvm.debug.dwarf.DIBaseItem;
import org.robovm.compiler.llvm.debug.dwarf.DICompileUnit;
import org.robovm.compiler.llvm.debug.dwarf.DICompositeType;
import org.robovm.compiler.llvm.debug.dwarf.DIDerivedType;
import org.robovm.compiler.llvm.debug.dwarf.DIFileDescriptor;
import org.robovm.compiler.llvm.debug.dwarf.DIItemList;
import org.robovm.compiler.llvm.debug.dwarf.DILineNumber;
import org.robovm.compiler.llvm.debug.dwarf.DILocalVariable;
import org.robovm.compiler.llvm.debug.dwarf.DIMutableItemList;
import org.robovm.compiler.llvm.debug.dwarf.DISubprogram;
import org.robovm.compiler.llvm.debug.dwarf.DwarfConst;
import org.robovm.compiler.plugin.AbstractCompilerPlugin;
import org.robovm.compiler.plugin.PluginArguments;
import org.robovm.compiler.plugin.debug.kotlin.KotlinTools;
import org.robovm.debugger.debuginfo.DebuggerDebugAllocaInfo;
import org.robovm.debugger.debuginfo.DebuggerDebugMethodInfo;
import org.robovm.debugger.debuginfo.DebuggerDebugObjectFileInfo;
import org.robovm.debugger.debuginfo.DebuggerDebugVariableInfo;
import org.robovm.llvm.LineInfo;
import org.robovm.llvm.ObjectFile;
import org.robovm.llvm.SectionIterator;
import org.robovm.llvm.Symbol;
import org.robovm.llvm.debuginfo.DwarfDebugMethodInfo;
import org.robovm.llvm.debuginfo.DwarfDebugObjectFileInfo;
import org.robovm.llvm.debuginfo.DwarfDebugVariableInfo;
import soot.Local;
import soot.LocalVariable;
import soot.SootMethod;
import soot.Unit;
import soot.jimple.IdentityStmt;
import soot.jimple.ParameterRef;
import soot.jimple.internal.JIdentityStmt;
import soot.tagkit.GenericAttribute;
import soot.tagkit.LineNumberTag;
import soot.tagkit.SourceFileTag;
import soot.util.Chain;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
/**
* provides only line number debug information for now
*/
public class DebugInformationPlugin extends AbstractCompilerPlugin {
public DebugInformationPlugin() {
}
@Override
public void beforeConfig(Config.Builder builder, Config config) {
if (config.isDebug()) {
// debugger depends on amount of symbols.
// as strip removes all local symbols all dependencies need to be converted
// into exported ones, adding wildcards
// nb: linker doesn't support espaping in wildcards
// so "[[]" works actually as "\["
builder.addExportedSymbol("*[[]debuginfo]");
builder.addExportedSymbol("*[[]bptable]");
builder.addExportedSymbol("prim_*");
builder.addExportedSymbol("_bcBootClassesHash");
builder.addExportedSymbol("_bcClassesHash");
builder.addExportedSymbol("robovmBaseSymbol");
}
}
public PluginArguments getArguments() {
return new PluginArguments("debug", Collections.emptyList());
}
@Override
public void helloClass(Config config, Clazz clazz) {
super.helloClass(config, clazz);
ClassDataBundle classBundle = clazz.getAttachment(ClassDataBundle.class);
if (classBundle != null)
clazz.removeAttachement(classBundle);
// keep all data for class in one structure, allows to reset thing by placing null there
classBundle = new ClassDataBundle();
clazz.attach(classBundle);
if (config.isDebug()) {
// make a list of java methods as it is in class
// as during compilation class going to be heavily adjusted and lot of synthetics method will appear
classBundle.methodsBeforeCompile = new HashSet<>();
for (SootMethod m : clazz.getSootClass().getMethods()) {
if (m.isAbstract() || m.isNative())
continue;
classBundle.methodsBeforeCompile.add(m.getSignature());
}
}
}
@Override
public void beforeClass(Config config, Clazz clazz, ModuleBuilder mb) throws IOException {
super.beforeClass(config, clazz, mb);
ClassDataBundle classBundle = clazz.getAttachment(ClassDataBundle.class);
classBundle.diFile = new DIItemList(mb, v(getDwarfSourceFile(clazz)), v(getDwarfSourceFilePath(clazz)));
classBundle.diFileDescriptor = new DIFileDescriptor(mb, classBundle.diFile);
classBundle.diMethods = new DIMutableItemList<>(mb);
classBundle.diCompileUnit = new DICompileUnit(mb, "llvm.dbg.cu", classBundle.diFile, classBundle.diMethods);
DIItemList dwarfVersion = new DIItemList(v(2), v("Dwarf Version"), v(2));
DIItemList debugInfoVersion = new DIItemList(v(2), v("Debug Info Version"), v(2));
classBundle.flags = new DIItemList(mb, "llvm.module.flags", dwarfVersion.get(), debugInfoVersion.get());
if (config.isDebug()) {
// create dummy variable type
// today this information is not required as everything is received on java level
classBundle.dummyJavaVariableType = new DIDerivedType(mb, DwarfConst.Tag.TAG_pointer_type,
"DummyType", 0, 32, 32, classBundle.diFile, null);
// create a list where method inforation will be saved
classBundle.methods = new ArrayList<>();
// register llvm.dbg.declare
mb.addFunctionDeclaration(new FunctionDeclaration(Functions.LLVM_DBG_DECLARE));
if (config.getTarget().getArch().isArm()) {
// add global variable to emit sp-fp offset
// refer to 04-emit-sp-fp-offset-on-arm for details
mb.addGlobal(new Global("robovm.emitSpFpOffsets", Type.I8));
}
}
// kotlin uses source line remapping as it injects collections code and so on
LineNumberMapper lineNumberMapper = LineNumberMapper.DIRECT;
SourceFileTag sourceFileTag = (SourceFileTag) clazz.getSootClass().getTag("SourceFileTag");
if (sourceFileTag != null && sourceFileTag.getSourceFile() != null && sourceFileTag.getSourceFile().endsWith(".kt")) {
// kotlin, get line number mapping table from SMAP section
GenericAttribute smap = (GenericAttribute) clazz.getSootClass().getTag("SourceDebugExtension");
if (smap != null) {
lineNumberMapper = KotlinTools.parseSMAP(config, smap.getValue(), clazz.getInternalName());
}
}
// save mapper
clazz.attach(lineNumberMapper);
}
@Override
public void afterMethod(Config config, Clazz clazz, SootMethod method, ModuleBuilder mb, Function function) throws IOException {
super.afterMethod(config, clazz, method, mb, function);
ClassDataBundle classBundle = clazz.getAttachment(ClassDataBundle.class);
// don't try to generate shadow frames for native or abstract methods
// or methods that don't have any instructions in them
if (method.isNative() || method.isAbstract() || !method.hasActiveBody()) {
return;
}
BasicBlock entryBlock = function.getBasicBlocks().get(0);
//Method has only a return null statement
if (entryBlock.getInstructions().size() == 1) {
return;
}
// fill subroutine type
DICompositeType diSubprogramType = new DICompositeType(mb);
diSubprogramType.setTypeTag(DwarfConst.Tag.TAG_subroutine_type);
diSubprogramType.setFile(classBundle.diFile);
diSubprogramType.setFileContext(classBundle.diFileDescriptor);
// skip other fields for now as not required for line numbers
DISubprogram diSubprogram = new DISubprogram(mb);
diSubprogram.setSubrotineType(diSubprogramType);
diSubprogram.setSignature(function.getName());
diSubprogram.setFile(classBundle.diFile);
diSubprogram.setFileContext(classBundle.diFileDescriptor);
diSubprogram.setLlvmFunction(function.ref());
// find out if debug information to be fetched for this method
// skip debug information for class initializer, generated callbacks and bridge methods
boolean includeDebuggerInfo = config.isDebug()
&& !Annotations.hasCallbackAnnotation(method)
&& !Annotations.hasBridgeAnnotation(method)
&& classBundle.methodsBeforeCompile.contains(method.getSignature());
// build per-unit local snapshot map
DebuggerDebugVariableSlicer localsDebugInfo = null;
if (includeDebuggerInfo) {
// build local variables map
localsDebugInfo = new DebuggerDebugVariableSlicer(config, method);
}
// maps instruction to line number -- for debugger hooks injection
Map instructionToLineNo = new HashMap<>();
Map instructionToDebugInfoIdx = new HashMap<>();
Map unitToInstruction = new HashMap<>();
// pick up created line number mapper to remap line numbers for kotlin. for pure java it provides
// x->x mapping
LineNumberMapper lineNumberMapper = clazz.getAttachment(LineNumberMapper.class);
// insert line number and additional debug information
// column is used as index for additional debug information, once it is compiled for each code position
// be possible to pick up variables list that are visible at program counter
int methodLineNumber = Integer.MAX_VALUE;
int methodEndLineNumber = Integer.MIN_VALUE;
for (BasicBlock bb : function.getBasicBlocks()) {
for (Instruction instruction : bb.getInstructions()) {
int lineNumber = -1;
int unmappedLineNumber = -1;
int columnAsDebugInfoIdx = 0;
List