Improve symbolicator, generate better debug info (#2488)
This commit is contained in:
+1
-1
@@ -89,7 +89,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun generateLocationInfo(locationInfo: LocationInfo): DILocationRef? {
|
fun generateLocationInfo(locationInfo: LocationInfo): DILocationRef? {
|
||||||
return LLVMCreateLocation(LLVMGetModuleContext(context.llvmModule), locationInfo.line, locationInfo.line, locationInfo.scope)
|
return LLVMCreateLocation(LLVMGetModuleContext(context.llvmModule), locationInfo.line, locationInfo.column, locationInfo.scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
val objCDataGenerator = when (context.config.target.family) {
|
val objCDataGenerator = when (context.config.target.family) {
|
||||||
|
|||||||
+24
-16
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin
|
|||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.SourceManager
|
import org.jetbrains.kotlin.ir.SourceManager
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor
|
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
@@ -728,8 +729,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
if (body == null) return
|
if (body == null) return
|
||||||
|
|
||||||
generateFunction(codegen, declaration,
|
generateFunction(codegen, declaration,
|
||||||
declaration.location(declaration.startLine(), declaration.startColumn()),
|
declaration.location(start = true),
|
||||||
declaration.location(declaration.endLine(), declaration.endColumn())) {
|
declaration.location(start = false)) {
|
||||||
using(FunctionScope(declaration, it)) {
|
using(FunctionScope(declaration, it)) {
|
||||||
val parameterScope = ParameterScope(declaration, functionGenerationContext)
|
val parameterScope = ParameterScope(declaration, functionGenerationContext)
|
||||||
using(parameterScope) {
|
using(parameterScope) {
|
||||||
@@ -755,11 +756,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
"${declaration.descriptor.containingDeclaration}::${ir2string(declaration)}")
|
"${declaration.descriptor.containingDeclaration}::${ir2string(declaration)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrFunction.location(line: Int, column:Int) =
|
private fun IrFunction.location(start: Boolean) =
|
||||||
if (context.shouldContainDebugInfo()) LocationInfo(
|
if (context.shouldContainDebugInfo() && startOffset != UNDEFINED_OFFSET) LocationInfo(
|
||||||
scope = scope()!!,
|
scope = scope()!!,
|
||||||
line = line,
|
line = if (start) startLine() else endLine(),
|
||||||
column = column)
|
column = if (start) startColumn() else endColumn())
|
||||||
else null
|
else null
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -920,8 +921,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
* Creates new [ContinuationBlock] that receives the value of given Kotlin type
|
* Creates new [ContinuationBlock] that receives the value of given Kotlin type
|
||||||
* and generates [code] starting from its beginning.
|
* and generates [code] starting from its beginning.
|
||||||
*/
|
*/
|
||||||
private fun continuationBlock(type: IrType,
|
private fun continuationBlock(
|
||||||
locationInfo: LocationInfo?, code: (ContinuationBlock) -> Unit = {}): ContinuationBlock {
|
type: IrType, locationInfo: LocationInfo?, code: (ContinuationBlock) -> Unit = {}): ContinuationBlock {
|
||||||
|
|
||||||
val entry = functionGenerationContext.basicBlock("continuation_block", locationInfo)
|
val entry = functionGenerationContext.basicBlock("continuation_block", locationInfo)
|
||||||
|
|
||||||
functionGenerationContext.appendingTo(entry) {
|
functionGenerationContext.appendingTo(entry) {
|
||||||
@@ -1697,7 +1699,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private open inner class FileScope(val file:IrFile) : InnerScopeImpl() {
|
private open inner class FileScope(val file: IrFile) : InnerScopeImpl() {
|
||||||
override fun fileScope(): CodeContext? = this
|
override fun fileScope(): CodeContext? = this
|
||||||
|
|
||||||
override fun location(line: Int, column: Int) = scope()?.let {LocationInfo(it, line, column) }
|
override fun location(line: Int, column: Int) = scope()?.let {LocationInfo(it, line, column) }
|
||||||
@@ -1856,17 +1858,19 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
private fun file() = (currentCodeContext.fileScope() as FileScope).file
|
private fun file() = (currentCodeContext.fileScope() as FileScope).file
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
private fun updateBuilderDebugLocation(element: IrElement):DILocationRef? {
|
private fun updateBuilderDebugLocation(element: IrElement): DILocationRef? {
|
||||||
if (!context.shouldContainDebugInfo() || currentCodeContext.functionScope() == null) return null
|
if (!context.shouldContainDebugInfo() || currentCodeContext.functionScope() == null) return null
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return element.startLocation?.let{functionGenerationContext.debugLocation(it)}
|
return element.startLocation?.let{ functionGenerationContext.debugLocation(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IrElement.startLocation: LocationInfo?
|
private val IrElement.startLocation: LocationInfo?
|
||||||
get() = currentCodeContext.location(startLine(), startColumn())
|
get() = if (startOffset == UNDEFINED_OFFSET) null
|
||||||
|
else currentCodeContext.location(startLine(), startColumn())
|
||||||
|
|
||||||
private val IrElement.endLocation: LocationInfo?
|
private val IrElement.endLocation: LocationInfo?
|
||||||
get() = currentCodeContext.location(endLine(), endColumn())
|
get() = if (startOffset == UNDEFINED_OFFSET) null
|
||||||
|
else currentCodeContext.location(endLine(), endColumn())
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
private fun IrElement.startLine() = file().fileEntry.line(this.startOffset)
|
private fun IrElement.startLine() = file().fileEntry.line(this.startOffset)
|
||||||
@@ -2497,6 +2501,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal data class LocationInfo(val scope:DIScopeOpaqueRef,
|
internal data class LocationInfo(val scope: DIScopeOpaqueRef,
|
||||||
val line:Int,
|
val line: Int,
|
||||||
val column:Int)
|
val column: Int) {
|
||||||
|
init {
|
||||||
|
assert(line != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ const char* CSSourceInfoGetPath(CSSourceInfoRef info);
|
|||||||
const char* CSSourceInfoGetFilename(CSSourceInfoRef info);
|
const char* CSSourceInfoGetFilename(CSSourceInfoRef info);
|
||||||
|
|
||||||
uint32_t CSSourceInfoGetLineNumber(CSSourceInfoRef info);
|
uint32_t CSSourceInfoGetLineNumber(CSSourceInfoRef info);
|
||||||
|
uint32_t CSSourceInfoGetColumn(CSSourceInfoRef info);
|
||||||
|
|
||||||
CSTypeRef CSRetain(CSTypeRef);
|
CSTypeRef CSRetain(CSTypeRef);
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,32 @@ fun archToCpuName(arch: String): cpu_type_t = when (arch) {
|
|||||||
else -> TODO("unsupported $arch")
|
else -> TODO("unsupported $arch")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun sourceInfoString(owner: CValue<CSSymbolOwnerRef>, address: ULong): String? {
|
||||||
|
var sourceInfo: CValue<CSTypeRef>? = CSSymbolOwnerGetSourceInfoWithAddress(owner, address)
|
||||||
|
if (CSIsNull(sourceInfo!!)) return null
|
||||||
|
var lineNumber = CSSourceInfoGetLineNumber(sourceInfo)
|
||||||
|
var maybe = false
|
||||||
|
if (lineNumber == 0u) {
|
||||||
|
// Workaround compiler bug.
|
||||||
|
sourceInfo = null
|
||||||
|
for (maybeAddress in address - 10u .. address + 10u) {
|
||||||
|
val maybeSourceInfo = CSSymbolOwnerGetSourceInfoWithAddress(owner, maybeAddress)
|
||||||
|
if (CSIsNull(maybeSourceInfo)) continue
|
||||||
|
var maybeLineNumber = CSSourceInfoGetLineNumber(maybeSourceInfo)
|
||||||
|
if (maybeLineNumber != 0u) {
|
||||||
|
lineNumber = maybeLineNumber
|
||||||
|
sourceInfo = maybeSourceInfo
|
||||||
|
maybe = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sourceInfo == null) return null
|
||||||
|
val filePath = CSSourceInfoGetPath(sourceInfo)?.toKString() ?: return null
|
||||||
|
val columnNumber = CSSourceInfoGetColumn(sourceInfo)
|
||||||
|
return "$filePath:${if (maybe) "~" else ""}$lineNumber:$columnNumber"
|
||||||
|
}
|
||||||
|
|
||||||
fun analyzeTrace(program: String, arch: String, input: Sequence<String>) {
|
fun analyzeTrace(program: String, arch: String, input: Sequence<String>) {
|
||||||
val symbolicator = CSSymbolicatorCreateWithPathAndArchitecture(program, archToCpuName(arch))
|
val symbolicator = CSSymbolicatorCreateWithPathAndArchitecture(program, archToCpuName(arch))
|
||||||
if (CSIsNull(symbolicator)) throw Error("Cannot create \"$arch\" symbolicator for $program")
|
if (CSIsNull(symbolicator)) throw Error("Cannot create \"$arch\" symbolicator for $program")
|
||||||
@@ -39,15 +65,9 @@ fun analyzeTrace(program: String, arch: String, input: Sequence<String>) {
|
|||||||
if (!CSIsNull(symbol)) {
|
if (!CSIsNull(symbol)) {
|
||||||
CSSymbolGetRange(symbol).useContents {
|
CSSymbolGetRange(symbol).useContents {
|
||||||
val address = this.location + offsetInFunction
|
val address = this.location + offsetInFunction
|
||||||
val sourceInfo = CSSymbolOwnerGetSourceInfoWithAddress(owner, address)
|
val sourceInfo = sourceInfoString(owner, address)
|
||||||
if (!CSIsNull(sourceInfo)) {
|
if (sourceInfo != null) {
|
||||||
val filePath = CSSourceInfoGetPath(sourceInfo)?.toKString()
|
result = matcher.replaceFirst(line, "$atPart$functionName $sourceInfo")
|
||||||
// or val fileName = CSSourceInfoGetFilename(sourceInfo)?.toKString()
|
|
||||||
val lineNumber = CSSourceInfoGetLineNumber(sourceInfo)
|
|
||||||
val lineNumberString = if (lineNumber != 0u) lineNumber.toString() else "<unknown>"
|
|
||||||
if (filePath != null)
|
|
||||||
result = matcher.replaceFirst(line,
|
|
||||||
"$atPart$functionName $filePath:$lineNumberString")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user