[codegen][debug info][dwarf] (var) variable inspection in debugger support
- debug location metainformation attached to stack allcated slots. - python bindings to work such variables.
This commit is contained in:
committed by
Vasily Levchenko
parent
4931b2f05b
commit
db1a1b029a
+36
-9
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
@@ -110,9 +109,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
get() = (functionDescriptor as? ClassConstructorDescriptor)?.constructedClass
|
||||
private var returnSlot: LLVMValueRef? = null
|
||||
private var slotsPhi: LLVMValueRef? = null
|
||||
private var slotCount = 0
|
||||
private var slotCount = 1
|
||||
private var localAllocs = 0
|
||||
private var arenaSlot: LLVMValueRef? = null
|
||||
private val slotToVariableLocation = mutableMapOf<Int,VariableDebugLocation>()
|
||||
|
||||
private val prologueBb = basicBlockInFunction("prologue", startLocation)
|
||||
private val localsInitBb = basicBlockInFunction("locals_init", startLocation)
|
||||
@@ -142,15 +142,31 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
return result
|
||||
}
|
||||
|
||||
fun alloca(type: LLVMTypeRef?, name: String = ""): LLVMValueRef {
|
||||
fun alloca(type: LLVMTypeRef?, name: String = "", variableLocation: VariableDebugLocation? = null): LLVMValueRef {
|
||||
if (isObjectType(type!!)) {
|
||||
appendingTo(localsInitBb) {
|
||||
return gep(slotsPhi!!, Int32(slotCount++).llvm, name)
|
||||
val slotAddress = gep(slotsPhi!!, Int32(slotCount).llvm, name)
|
||||
variableLocation?.let {
|
||||
slotToVariableLocation[slotCount] = it
|
||||
}
|
||||
slotCount++
|
||||
return slotAddress
|
||||
}
|
||||
}
|
||||
|
||||
appendingTo(prologueBb) {
|
||||
return LLVMBuildAlloca(builder, type, name)!!
|
||||
val slotAddress = LLVMBuildAlloca(builder, type, name)!!
|
||||
variableLocation?.let {
|
||||
DIInsertDeclaration(
|
||||
builder = codegen.context.debugInfo.builder,
|
||||
value = slotAddress,
|
||||
localVariable = it.localVariable,
|
||||
location = it.location,
|
||||
bb = prologueBb,
|
||||
expr = null,
|
||||
exprCount = 0)
|
||||
}
|
||||
return slotAddress
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +195,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
fun loadSlot(address: LLVMValueRef, isVar: Boolean, name: String = ""): LLVMValueRef {
|
||||
val value = LLVMBuildLoad(builder, address, name)!!
|
||||
if (isObjectRef(value) && isVar) {
|
||||
val slot = alloca(LLVMTypeOf(value))
|
||||
val slot = alloca(LLVMTypeOf(value), variableLocation = null)
|
||||
storeAnyLocal(value, slot)
|
||||
}
|
||||
return value
|
||||
@@ -465,9 +481,6 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
}
|
||||
positionAtEnd(localsInitBb)
|
||||
slotsPhi = phi(kObjHeaderPtrPtr)
|
||||
// First slot can be assigned to keep pointer to frame local arena.
|
||||
slotCount = 1
|
||||
localAllocs = 0
|
||||
// Is removed by DCE trivially, if not needed.
|
||||
arenaSlot = intToPtr(
|
||||
or(ptrToInt(slotsPhi, codegen.intPtrType), codegen.immOneIntPtrType), kObjHeaderPtrPtr)
|
||||
@@ -491,6 +504,20 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
Int1(0).llvm))
|
||||
}
|
||||
addPhiIncoming(slotsPhi!!, prologueBb to slots)
|
||||
val slotOffset = pointerSize * slotCount
|
||||
memScoped {
|
||||
slotToVariableLocation.forEach { slot, variable ->
|
||||
val expr = longArrayOf(DwarfOp.DW_OP_minus.value, slotOffset + pointerSize * slot.toLong()).toCValues()
|
||||
DIInsertDeclaration(
|
||||
builder = codegen.context.debugInfo.builder,
|
||||
value = slotsPhi,
|
||||
localVariable = variable.localVariable,
|
||||
location = variable.location,
|
||||
bb = prologueBb,
|
||||
expr = expr,
|
||||
exprCount = 2)
|
||||
}
|
||||
}
|
||||
br(localsInitBb)
|
||||
}
|
||||
|
||||
|
||||
+52
-54
@@ -20,15 +20,14 @@ import kotlinx.cinterop.allocArrayOf
|
||||
import kotlinx.cinterop.memScoped
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.backend.konan.KonanVersion
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.SourceManager.FileEntry
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
@@ -104,23 +103,23 @@ internal fun generateDebugInfoHeader(context: Context) {
|
||||
|
||||
val path = context.config.outputFile
|
||||
.toFileAndFolder()
|
||||
|
||||
context.debugInfo.module = DICreateModule(
|
||||
builder = context.debugInfo.builder,
|
||||
scope = context.llvmModule as DIScopeOpaqueRef,
|
||||
name = path.path(),
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
context.debugInfo.module = DICreateModule(
|
||||
builder = context.debugInfo.builder,
|
||||
scope = context.llvmModule as DIScopeOpaqueRef,
|
||||
name = path.path(),
|
||||
configurationMacro = "",
|
||||
includePath = "",
|
||||
iSysRoot = "")
|
||||
includePath = "",
|
||||
iSysRoot = "")
|
||||
context.debugInfo.compilationModule = DICreateCompilationUnit(
|
||||
builder = context.debugInfo.builder,
|
||||
lang = DwarfLanguage.DW_LANG_Kotlin.value,
|
||||
File = path.file,
|
||||
dir = path.folder,
|
||||
producer = DWARF.producer,
|
||||
builder = context.debugInfo.builder,
|
||||
lang = DwarfLanguage.DW_LANG_Kotlin.value,
|
||||
File = path.file,
|
||||
dir = path.folder,
|
||||
producer = DWARF.producer,
|
||||
isOptimized = 0,
|
||||
flags = "",
|
||||
rv = DWARF.runtimeVersion)
|
||||
flags = "",
|
||||
rv = DWARF.runtimeVersion)
|
||||
/* TODO: figure out what here 2 means:
|
||||
*
|
||||
* 0:b-backend-dwarf:minamoto@minamoto-osx(0)# cat /dev/null | clang -xc -S -emit-llvm -g -o - -
|
||||
@@ -152,39 +151,35 @@ internal fun generateDebugInfoHeader(context: Context) {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal fun KotlinType.dwarfType(context:Context, targetData:LLVMTargetDataRef): DITypeOpaqueRef {
|
||||
return when {
|
||||
KotlinBuiltIns.isPrimitiveType(this) -> debugInfoBaseType(context, targetData, this.getJetTypeFqName(false), llvmType(context), encoding(context).value.toInt())
|
||||
when {
|
||||
KotlinBuiltIns.isPrimitiveType(this) -> return debugInfoBaseType(context, targetData, this.getJetTypeFqName(false), llvmType(context), encoding(context).value.toInt())
|
||||
KotlinBuiltIns.isArray(this) -> {
|
||||
val arrayElementType = context.builtIns.getArrayElementType(this)
|
||||
DICreateArrayType(context.debugInfo.builder, arrayElementType.size(context), arrayElementType.alignment(context),
|
||||
return DICreateArrayType(context.debugInfo.builder, arrayElementType.size(context), arrayElementType.alignment(context),
|
||||
arrayElementType.diType(context, targetData), 1) as DITypeOpaqueRef
|
||||
}
|
||||
else -> {
|
||||
val classDescriptor = TypeUtils.getClassDescriptor(this)
|
||||
if (classDescriptor != null) {
|
||||
/**
|
||||
* Ideally we'd use [KotlinType.typeInfoSymbolName] here , by type could be not
|
||||
* exportable.
|
||||
*/
|
||||
DICreateStructType(
|
||||
refBuilder = context.debugInfo.builder,
|
||||
scope = context.debugInfo.compilationModule as DIScopeOpaqueRef,
|
||||
name = "ktype:${classDescriptor.fqNameSafe}",
|
||||
file = null,
|
||||
lineNumber = 0,
|
||||
sizeInBits = 0,
|
||||
alignInBits = 0,
|
||||
flags = DWARF.flagsForwardDeclaration,
|
||||
derivedFrom = null,
|
||||
elements = null,
|
||||
elementsCount = 0,
|
||||
refPlace = null)!! as DITypeOpaqueRef
|
||||
}
|
||||
else if (TypeUtils.isTypeParameter(this)){
|
||||
//TODO: Type parameter, how to deal with if?
|
||||
debugInfoBaseType(context, targetData, this.toString(), llvmType(context), encoding(context).value.toInt())
|
||||
} else {
|
||||
TODO("$this: Does this case really exist?")
|
||||
return when {
|
||||
classDescriptor != null -> {
|
||||
val type = DICreateStructType(
|
||||
refBuilder = context.debugInfo.builder,
|
||||
scope = context.debugInfo.compilationModule as DIScopeOpaqueRef,
|
||||
name = "ObjHeader",
|
||||
file = null,
|
||||
lineNumber = 0,
|
||||
sizeInBits = 0,
|
||||
alignInBits = 0,
|
||||
flags = DWARF.flagsForwardDeclaration,
|
||||
derivedFrom = null,
|
||||
elements = null,
|
||||
elementsCount = 0,
|
||||
refPlace = null)!! as DITypeOpaqueRef
|
||||
dwarfPointerType(context, type)
|
||||
}
|
||||
TypeUtils.isTypeParameter(this) -> //TODO: Type parameter, how to deal with if?
|
||||
debugInfoBaseType(context, targetData, this.toString(), llvmType(context), encoding(context).value.toInt())
|
||||
else -> TODO("$this: Does this case really exist?")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,17 +210,16 @@ internal fun KotlinType.alignment(context:Context) = context.debugInfo.llvmTypeA
|
||||
internal fun KotlinType.llvmType(context:Context): LLVMTypeRef = context.debugInfo.llvmTypes.getOrDefault(this, context.debugInfo.otherLlvmType)
|
||||
|
||||
private fun<T> or(v:T, vararg p:(T)->Boolean):Boolean = p.any{it(v)}
|
||||
internal fun KotlinType.encoding(context:Context):DwarfTypeKind {
|
||||
return when {
|
||||
this in context.debugInfo.intTypes -> DwarfTypeKind.DW_ATE_signed
|
||||
this in context.debugInfo.realTypes -> DwarfTypeKind.DW_ATE_float
|
||||
KotlinBuiltIns.isBoolean(this) -> DwarfTypeKind.DW_ATE_boolean
|
||||
KotlinBuiltIns.isChar(this) -> DwarfTypeKind.DW_ATE_unsigned
|
||||
(!KotlinBuiltIns.isPrimitiveType(this)) -> DwarfTypeKind.DW_ATE_address
|
||||
else -> TODO(toString())
|
||||
|
||||
}
|
||||
}
|
||||
internal fun KotlinType.encoding(context:Context):DwarfTypeKind = when {
|
||||
this in context.debugInfo.intTypes -> DwarfTypeKind.DW_ATE_signed
|
||||
this in context.debugInfo.realTypes -> DwarfTypeKind.DW_ATE_float
|
||||
KotlinBuiltIns.isBoolean(this) -> DwarfTypeKind.DW_ATE_boolean
|
||||
KotlinBuiltIns.isChar(this) -> DwarfTypeKind.DW_ATE_unsigned
|
||||
(!KotlinBuiltIns.isPrimitiveType(this)) -> DwarfTypeKind.DW_ATE_address
|
||||
else -> TODO(toString())
|
||||
}
|
||||
|
||||
internal fun alignTo(value:Long, align:Long):Long = (value + align - 1) / align * align
|
||||
|
||||
internal fun FunctionDescriptor.subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef): DISubroutineTypeRef {
|
||||
@@ -242,5 +236,9 @@ private fun KotlinType.referenceOrValue(context: Context, llvmTargetData: LLVMTa
|
||||
return if (KotlinBuiltIns.isPrimitiveType(this))
|
||||
refType
|
||||
else
|
||||
DICreateReferenceType(context.debugInfo.builder, refType) as DITypeOpaqueRef
|
||||
dwarfPointerType(context, refType)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun dwarfPointerType(context: Context, type: DITypeOpaqueRef) =
|
||||
DICreatePointerType(context.debugInfo.builder, type) as DITypeOpaqueRef
|
||||
|
||||
+163
-1
@@ -97,7 +97,8 @@ internal enum class DwarfTag(val value:Int) {
|
||||
DW_TAG_BORLAND_Delphi_set(0xb003),
|
||||
DW_TAG_BORLAND_Delphi_variant(0xb004),
|
||||
}
|
||||
internal enum class DwarfTypeKind(val value:Byte) {
|
||||
|
||||
internal enum class DwarfTypeKind(val value:Byte) {
|
||||
DW_ATE_address(0x01),
|
||||
DW_ATE_boolean(0x02),
|
||||
DW_ATE_complex_float(0x03),
|
||||
@@ -115,6 +116,167 @@ internal enum class DwarfTag(val value:Int) {
|
||||
DW_ATE_decimal_float(0x0f),
|
||||
DW_ATE_UTF(0x10),
|
||||
}
|
||||
|
||||
internal enum class DwarfOp(val value:Long) {
|
||||
DW_OP_addr(0x03),
|
||||
DW_OP_deref(0x06),
|
||||
DW_OP_const1u(0x08),
|
||||
DW_OP_const1s(0x09),
|
||||
DW_OP_const2u(0x0a),
|
||||
DW_OP_const2s(0x0b),
|
||||
DW_OP_const4u(0x0c),
|
||||
DW_OP_const4s(0x0d),
|
||||
DW_OP_const8u(0x0e),
|
||||
DW_OP_const8s(0x0f),
|
||||
DW_OP_constu(0x10),
|
||||
DW_OP_consts(0x11),
|
||||
DW_OP_dup(0x12),
|
||||
DW_OP_drop(0x13),
|
||||
DW_OP_over(0x14),
|
||||
DW_OP_pick(0x15),
|
||||
DW_OP_swap(0x16),
|
||||
DW_OP_rot(0x17),
|
||||
DW_OP_xderef(0x18),
|
||||
DW_OP_abs(0x19),
|
||||
DW_OP_and(0x1a),
|
||||
DW_OP_div(0x1b),
|
||||
DW_OP_minus(0x1c),
|
||||
DW_OP_mod(0x1d),
|
||||
DW_OP_mul(0x1e),
|
||||
DW_OP_neg(0x1f),
|
||||
DW_OP_not(0x20),
|
||||
DW_OP_or(0x21),
|
||||
DW_OP_plus(0x22),
|
||||
DW_OP_plus_uconst(0x23),
|
||||
DW_OP_shl(0x24),
|
||||
DW_OP_shr(0x25),
|
||||
DW_OP_shra(0x26),
|
||||
DW_OP_xor(0x27),
|
||||
DW_OP_skip(0x2f),
|
||||
DW_OP_bra(0x28),
|
||||
DW_OP_eq(0x29),
|
||||
DW_OP_ge(0x2a),
|
||||
DW_OP_gt(0x2b),
|
||||
DW_OP_le(0x2c),
|
||||
DW_OP_lt(0x2d),
|
||||
DW_OP_ne(0x2e),
|
||||
DW_OP_lit0(0x30),
|
||||
DW_OP_lit1(0x31),
|
||||
DW_OP_lit2(0x32),
|
||||
DW_OP_lit3(0x33),
|
||||
DW_OP_lit4(0x34),
|
||||
DW_OP_lit5(0x35),
|
||||
DW_OP_lit6(0x36),
|
||||
DW_OP_lit7(0x37),
|
||||
DW_OP_lit8(0x38),
|
||||
DW_OP_lit9(0x39),
|
||||
DW_OP_lit10(0x3a),
|
||||
DW_OP_lit11(0x3b),
|
||||
DW_OP_lit12(0x3c),
|
||||
DW_OP_lit13(0x3d),
|
||||
DW_OP_lit14(0x3e),
|
||||
DW_OP_lit15(0x3f),
|
||||
DW_OP_lit16(0x40),
|
||||
DW_OP_lit17(0x41),
|
||||
DW_OP_lit18(0x42),
|
||||
DW_OP_lit19(0x43),
|
||||
DW_OP_lit20(0x44),
|
||||
DW_OP_lit21(0x45),
|
||||
DW_OP_lit22(0x46),
|
||||
DW_OP_lit23(0x47),
|
||||
DW_OP_lit24(0x48),
|
||||
DW_OP_lit25(0x49),
|
||||
DW_OP_lit26(0x4a),
|
||||
DW_OP_lit27(0x4b),
|
||||
DW_OP_lit28(0x4c),
|
||||
DW_OP_lit29(0x4d),
|
||||
DW_OP_lit30(0x4e),
|
||||
DW_OP_lit31(0x4f),
|
||||
DW_OP_reg0(0x50),
|
||||
DW_OP_reg1(0x51),
|
||||
DW_OP_reg2(0x52),
|
||||
DW_OP_reg3(0x53),
|
||||
DW_OP_reg4(0x54),
|
||||
DW_OP_reg5(0x55),
|
||||
DW_OP_reg6(0x56),
|
||||
DW_OP_reg7(0x57),
|
||||
DW_OP_reg8(0x58),
|
||||
DW_OP_reg9(0x59),
|
||||
DW_OP_reg10(0x5a),
|
||||
DW_OP_reg11(0x5b),
|
||||
DW_OP_reg12(0x5c),
|
||||
DW_OP_reg13(0x5d),
|
||||
DW_OP_reg14(0x5e),
|
||||
DW_OP_reg15(0x5f),
|
||||
DW_OP_reg16(0x60),
|
||||
DW_OP_reg17(0x61),
|
||||
DW_OP_reg18(0x62),
|
||||
DW_OP_reg19(0x63),
|
||||
DW_OP_reg20(0x64),
|
||||
DW_OP_reg21(0x65),
|
||||
DW_OP_reg22(0x66),
|
||||
DW_OP_reg23(0x67),
|
||||
DW_OP_reg24(0x68),
|
||||
DW_OP_reg25(0x69),
|
||||
DW_OP_reg26(0x6a),
|
||||
DW_OP_reg27(0x6b),
|
||||
DW_OP_reg28(0x6c),
|
||||
DW_OP_reg29(0x6d),
|
||||
DW_OP_reg30(0x6e),
|
||||
DW_OP_reg31(0x6f),
|
||||
DW_OP_breg0(0x70),
|
||||
DW_OP_breg1(0x71),
|
||||
DW_OP_breg2(0x72),
|
||||
DW_OP_breg3(0x73),
|
||||
DW_OP_breg4(0x74),
|
||||
DW_OP_breg5(0x75),
|
||||
DW_OP_breg6(0x76),
|
||||
DW_OP_breg7(0x77),
|
||||
DW_OP_breg8(0x78),
|
||||
DW_OP_breg9(0x79),
|
||||
DW_OP_breg10(0x7a),
|
||||
DW_OP_breg11(0x7b),
|
||||
DW_OP_breg12(0x7c),
|
||||
DW_OP_breg13(0x7d),
|
||||
DW_OP_breg14(0x7e),
|
||||
DW_OP_breg15(0x7f),
|
||||
DW_OP_breg16(0x80),
|
||||
DW_OP_breg17(0x81),
|
||||
DW_OP_breg18(0x82),
|
||||
DW_OP_breg19(0x83),
|
||||
DW_OP_breg20(0x84),
|
||||
DW_OP_breg21(0x85),
|
||||
DW_OP_breg22(0x86),
|
||||
DW_OP_breg23(0x87),
|
||||
DW_OP_breg24(0x88),
|
||||
DW_OP_breg25(0x89),
|
||||
DW_OP_breg26(0x8a),
|
||||
DW_OP_breg27(0x8b),
|
||||
DW_OP_breg28(0x8c),
|
||||
DW_OP_breg29(0x8d),
|
||||
DW_OP_breg30(0x8e),
|
||||
DW_OP_breg31(0x8f),
|
||||
DW_OP_regx(0x90),
|
||||
DW_OP_fbreg(0x91),
|
||||
DW_OP_bregx(0x92),
|
||||
DW_OP_piece(0x93),
|
||||
DW_OP_deref_size(0x94),
|
||||
DW_OP_xderef_size(0x95),
|
||||
DW_OP_nop(0x96),
|
||||
DW_OP_push_object_address(0x97),
|
||||
DW_OP_call2(0x98),
|
||||
DW_OP_call4(0x99),
|
||||
DW_OP_call_ref(0x9a),
|
||||
DW_OP_form_tls_address(0x9b),
|
||||
DW_OP_call_frame_cfa(0x9c),
|
||||
DW_OP_bit_piece(0x9d),
|
||||
DW_OP_implicit_value(0x9e),
|
||||
DW_OP_stack_value(0x9f),
|
||||
DW_OP_GNU_push_tls_address(0xe0),
|
||||
DW_OP_GNU_addr_index(0xfb),
|
||||
DW_OP_GNU_const_index(0xfc),
|
||||
}
|
||||
|
||||
internal enum class DwarfLanguage(val value:Int) {
|
||||
DW_LANG_C89(0x0001),
|
||||
DW_LANG_C(0x0002),
|
||||
|
||||
+9
-11
@@ -208,7 +208,7 @@ internal interface CodeContext {
|
||||
* Declares the variable.
|
||||
* @return index of declared variable.
|
||||
*/
|
||||
fun genDeclareVariable(descriptor: VariableDescriptor, value: LLVMValueRef?): Int
|
||||
fun genDeclareVariable(descriptor: VariableDescriptor, value: LLVMValueRef?, variableLocation: VariableDebugLocation?): Int
|
||||
|
||||
/**
|
||||
* @return index of variable declared before, or -1 if no such variable has been declared yet.
|
||||
@@ -276,7 +276,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
override fun genThrow(exception: LLVMValueRef) = unsupported()
|
||||
|
||||
override fun genDeclareVariable(descriptor: VariableDescriptor, value: LLVMValueRef?) = unsupported(descriptor)
|
||||
override fun genDeclareVariable(descriptor: VariableDescriptor, value: LLVMValueRef?, variableLocation: VariableDebugLocation?) = unsupported(descriptor)
|
||||
|
||||
override fun getDeclaredVariable(descriptor: VariableDescriptor) = -1
|
||||
|
||||
@@ -492,8 +492,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
*/
|
||||
private inner class VariableScope : InnerScopeImpl() {
|
||||
|
||||
override fun genDeclareVariable(descriptor: VariableDescriptor, value: LLVMValueRef?): Int {
|
||||
return functionGenerationContext.vars.createVariable(descriptor, value)
|
||||
override fun genDeclareVariable(descriptor: VariableDescriptor, value: LLVMValueRef?, variableLocation: VariableDebugLocation?): Int {
|
||||
return functionGenerationContext.vars.createVariable(descriptor, value, variableLocation)
|
||||
}
|
||||
|
||||
override fun getDeclaredVariable(descriptor: VariableDescriptor): Int {
|
||||
@@ -964,7 +964,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
for (catch in catches) {
|
||||
fun genCatchBlock() {
|
||||
using(VariableScope()) {
|
||||
currentCodeContext.genDeclareVariable(catch.parameter, exception)
|
||||
currentCodeContext.genDeclareVariable(catch.parameter, exception, null)
|
||||
evaluateExpressionAndJump(catch.result, success)
|
||||
}
|
||||
}
|
||||
@@ -1128,22 +1128,20 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
context.log{"generateVariable : ${ir2string(value)}"}
|
||||
val result = value.initializer?.let { evaluateExpression(it) }
|
||||
val variableDescriptor = value.descriptor
|
||||
val index = currentCodeContext.genDeclareVariable(variableDescriptor, result)
|
||||
if (context.shouldContainDebugInfo()) {
|
||||
val functionScope = (currentCodeContext.functionScope() as FunctionScope).declaration?.scope()
|
||||
val variableLocation = if (context.shouldContainDebugInfo() && functionScope != null && variableDescriptor.isVar) {
|
||||
val location = debugLocation(value)
|
||||
val functionScope = (currentCodeContext.functionScope() as FunctionScope).declaration?.scope() ?: return
|
||||
val file = (currentCodeContext.fileScope() as FileScope).file.file()
|
||||
val variable = functionGenerationContext.vars.load(index)
|
||||
val line = value.startLine()
|
||||
functionGenerationContext.vars.debugInfoLocalVariableLocation(
|
||||
functionScope = functionScope,
|
||||
diType = variableDescriptor.type.diType(context, functionGenerationContext.llvmTargetData),
|
||||
name = variableDescriptor.name,
|
||||
variable = variable,
|
||||
file = file,
|
||||
line = line,
|
||||
location = location)
|
||||
}
|
||||
} else null
|
||||
currentCodeContext.genDeclareVariable(variableDescriptor, result, variableLocation)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
+10
-12
@@ -51,7 +51,7 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
||||
contextVariablesToIndex.clear()
|
||||
}
|
||||
|
||||
fun createVariable(descriptor: VariableDescriptor, value: LLVMValueRef? = null) : Int {
|
||||
fun createVariable(descriptor: VariableDescriptor, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int {
|
||||
// Note that we always create slot for object references for memory management.
|
||||
if (!descriptor.isVar && value != null)
|
||||
return createImmutable(descriptor, value)
|
||||
@@ -60,15 +60,15 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
||||
// as even vals can be assigned on multiple paths. However, we use varness
|
||||
// knowledge, as anonymous slots are created only for true vars (for vals
|
||||
// their single assigner already have slot).
|
||||
return createMutable(descriptor, descriptor.isVar, value)
|
||||
return createMutable(descriptor, descriptor.isVar, value, variableLocation)
|
||||
}
|
||||
|
||||
fun createMutable(descriptor: VariableDescriptor,
|
||||
isVar: Boolean, value: LLVMValueRef? = null) : Int {
|
||||
isVar: Boolean, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int {
|
||||
assert(!contextVariablesToIndex.contains(descriptor))
|
||||
val index = variables.size
|
||||
val type = functionGenerationContext.getLLVMType(descriptor.type)
|
||||
val slot = functionGenerationContext.alloca(type, descriptor.name.asString())
|
||||
val slot = functionGenerationContext.alloca(type, descriptor.name.asString(), variableLocation)
|
||||
if (value != null)
|
||||
functionGenerationContext.storeAnyLocal(value, slot)
|
||||
variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), isVar))
|
||||
@@ -85,7 +85,7 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
||||
|
||||
private fun createAnonymousMutable(type: LLVMTypeRef, value: LLVMValueRef? = null) : Int {
|
||||
val index = variables.size
|
||||
val slot = functionGenerationContext.alloca(type)
|
||||
val slot = functionGenerationContext.alloca(type, variableLocation = null)
|
||||
if (value != null)
|
||||
functionGenerationContext.storeAnyLocal(value, slot)
|
||||
variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), true))
|
||||
@@ -117,7 +117,7 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
||||
variables[index].store(value)
|
||||
}
|
||||
|
||||
fun debugInfoLocalVariableLocation(functionScope: DIScopeOpaqueRef, diType: DITypeOpaqueRef, name:Name, variable: LLVMValueRef, file: DIFileRef, line: Int, location: DILocationRef?) {
|
||||
fun debugInfoLocalVariableLocation(functionScope: DIScopeOpaqueRef, diType: DITypeOpaqueRef, name:Name, file: DIFileRef, line: Int, location: DILocationRef?):VariableDebugLocation {
|
||||
val variableDeclaration = DICreateAutoVariable(
|
||||
builder = functionGenerationContext.context.debugInfo.builder,
|
||||
scope = functionScope,
|
||||
@@ -125,11 +125,9 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
|
||||
file = file,
|
||||
line = line,
|
||||
type = diType)
|
||||
DIInsertDeclarationWithEmptyExpression(
|
||||
builder = functionGenerationContext.context.debugInfo.builder,
|
||||
value = variable,
|
||||
localVariable = variableDeclaration,
|
||||
location = location,
|
||||
bb = LLVMGetInsertBlock(functionGenerationContext.builder))
|
||||
|
||||
return VariableDebugLocation(localVariable = variableDeclaration!!, location = location, file = file, line = line)
|
||||
}
|
||||
}
|
||||
|
||||
internal data class VariableDebugLocation(val localVariable: DILocalVariableRef, val location:DILocationRef?, val file:DIFileRef, val line:Int)
|
||||
@@ -33,6 +33,12 @@ internal enum class DwarfTypeKind(val value:Byte) {
|
||||
#undef HANDLE_DW_ATE
|
||||
}
|
||||
|
||||
internal enum class DwarfOp(val value:Long) {
|
||||
#define HANDLE_DW_OP(ID, NAME) DW_OP_##NAME(ID),
|
||||
#include "llvm/Support/Dwarf.def"
|
||||
#undef HANDLE_DW_OP
|
||||
}
|
||||
|
||||
internal enum class DwarfLanguage(val value:Int) {
|
||||
#define HANDLE_DW_LANG(ID, NAME) DW_LANG_##NAME(ID),
|
||||
#include "llvm/Support/Dwarf.def"
|
||||
|
||||
@@ -178,6 +178,12 @@ DIDerivedTypeRef DICreateReferenceType(DIBuilderRef refBuilder, DITypeOpaqueRef
|
||||
llvm::unwrap(refType)));
|
||||
}
|
||||
|
||||
DIDerivedTypeRef DICreatePointerType(DIBuilderRef refBuilder, DITypeOpaqueRef refType) {
|
||||
return llvm::wrap(llvm::unwrap(refBuilder)->createReferenceType(
|
||||
llvm::dwarf::DW_TAG_pointer_type,
|
||||
llvm::unwrap(refType)));
|
||||
}
|
||||
|
||||
DISubroutineTypeRef DICreateSubroutineType(DIBuilderRef builder,
|
||||
DITypeOpaqueRef* types,
|
||||
unsigned typesCount) {
|
||||
@@ -212,11 +218,14 @@ DIExpressionRef DICreateEmptyExpression(DIBuilderRef builder) {
|
||||
return llvm::wrap(llvm::unwrap(builder)->createExpression());
|
||||
}
|
||||
|
||||
void DIInsertDeclarationWithEmptyExpression(DIBuilderRef builder, LLVMValueRef value, DILocalVariableRef localVariable, DILocationRef location, LLVMBasicBlockRef bb) {
|
||||
void DIInsertDeclaration(DIBuilderRef builder, LLVMValueRef value, DILocalVariableRef localVariable, DILocationRef location, LLVMBasicBlockRef bb, int64_t *expr, uint64_t exprCount) {
|
||||
auto di_builder = llvm::unwrap(builder);
|
||||
std::vector<int64_t> expression;
|
||||
for (uint64_t i = 0; i < exprCount; ++i)
|
||||
expression.push_back(expr[i]);
|
||||
di_builder->insertDeclare(llvm::unwrap(value),
|
||||
llvm::unwrap(localVariable),
|
||||
di_builder->createExpression(),
|
||||
di_builder->createExpression(expression),
|
||||
llvm::unwrap(location),
|
||||
llvm::unwrap(bb));
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ DICompositeTypeRef DICreateArrayType(DIBuilderRef refBuilder,
|
||||
uint64_t elementsCount);
|
||||
|
||||
DIDerivedTypeRef DICreateReferenceType(DIBuilderRef refBuilder, DITypeOpaqueRef refType);
|
||||
DIDerivedTypeRef DICreatePointerType(DIBuilderRef refBuilder, DITypeOpaqueRef refType);
|
||||
DICompositeTypeRef DICreateReplaceableCompositeType(DIBuilderRef refBuilder,
|
||||
int tag,
|
||||
const char *name,
|
||||
@@ -92,7 +93,7 @@ DISubroutineTypeRef DICreateSubroutineType(DIBuilderRef builder,
|
||||
unsigned typesCount);
|
||||
|
||||
DILocalVariableRef DICreateAutoVariable(DIBuilderRef builder, DIScopeOpaqueRef scope, const char *name, DIFileRef file, unsigned line, DITypeOpaqueRef type);
|
||||
void DIInsertDeclarationWithEmptyExpression(DIBuilderRef builder, LLVMValueRef value, DILocalVariableRef localVariable, DILocationRef location, LLVMBasicBlockRef bb);
|
||||
void DIInsertDeclaration(DIBuilderRef builder, LLVMValueRef value, DILocalVariableRef localVariable, DILocationRef location, LLVMBasicBlockRef bb, int64_t *expr, uint64_t exprCount);
|
||||
DIExpressionRef DICreateEmptyExpression(DIBuilderRef builder);
|
||||
void DIFunctionAddSubprogram(LLVMValueRef fn, DISubprogramRef sp);
|
||||
DILocationRef LLVMBuilderSetDebugLocation(LLVMBuilderRef builder, unsigned line, unsigned col, DIScopeOpaqueRef scope);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
##
|
||||
# Copyright 2010-2017 JetBrains s.r.o.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
#
|
||||
# (lldb) command script import llvmDebugInfoC/src/scripts/konan_lldb.py
|
||||
# (lldb) show_variable
|
||||
#
|
||||
|
||||
import lldb
|
||||
import commands
|
||||
import optparse
|
||||
import shlex
|
||||
|
||||
def show_variable(debugger, command, result, internal_dict):
|
||||
debugger.GetCommandInterpreter().HandleCommand('expr -- Konan_DebugPrint(%s)' % command, result)
|
||||
return result
|
||||
|
||||
def __lldb_init_module(debugger, internal_dict):
|
||||
debugger.HandleCommand('command script add -f konan_lldb.show_variable show_variable')
|
||||
|
||||
Reference in New Issue
Block a user