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? {
|
||||
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) {
|
||||
|
||||
+24
-16
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.SourceManager
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
@@ -728,8 +729,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
if (body == null) return
|
||||
|
||||
generateFunction(codegen, declaration,
|
||||
declaration.location(declaration.startLine(), declaration.startColumn()),
|
||||
declaration.location(declaration.endLine(), declaration.endColumn())) {
|
||||
declaration.location(start = true),
|
||||
declaration.location(start = false)) {
|
||||
using(FunctionScope(declaration, it)) {
|
||||
val parameterScope = ParameterScope(declaration, functionGenerationContext)
|
||||
using(parameterScope) {
|
||||
@@ -755,11 +756,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
"${declaration.descriptor.containingDeclaration}::${ir2string(declaration)}")
|
||||
}
|
||||
|
||||
private fun IrFunction.location(line: Int, column:Int) =
|
||||
if (context.shouldContainDebugInfo()) LocationInfo(
|
||||
private fun IrFunction.location(start: Boolean) =
|
||||
if (context.shouldContainDebugInfo() && startOffset != UNDEFINED_OFFSET) LocationInfo(
|
||||
scope = scope()!!,
|
||||
line = line,
|
||||
column = column)
|
||||
line = if (start) startLine() else endLine(),
|
||||
column = if (start) startColumn() else endColumn())
|
||||
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
|
||||
* and generates [code] starting from its beginning.
|
||||
*/
|
||||
private fun continuationBlock(type: IrType,
|
||||
locationInfo: LocationInfo?, code: (ContinuationBlock) -> Unit = {}): ContinuationBlock {
|
||||
private fun continuationBlock(
|
||||
type: IrType, locationInfo: LocationInfo?, code: (ContinuationBlock) -> Unit = {}): ContinuationBlock {
|
||||
|
||||
val entry = functionGenerationContext.basicBlock("continuation_block", locationInfo)
|
||||
|
||||
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 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 updateBuilderDebugLocation(element: IrElement):DILocationRef? {
|
||||
private fun updateBuilderDebugLocation(element: IrElement): DILocationRef? {
|
||||
if (!context.shouldContainDebugInfo() || currentCodeContext.functionScope() == null) return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return element.startLocation?.let{functionGenerationContext.debugLocation(it)}
|
||||
return element.startLocation?.let{ functionGenerationContext.debugLocation(it) }
|
||||
}
|
||||
|
||||
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?
|
||||
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)
|
||||
@@ -2497,6 +2501,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
}
|
||||
|
||||
internal data class LocationInfo(val scope:DIScopeOpaqueRef,
|
||||
val line:Int,
|
||||
val column:Int)
|
||||
internal data class LocationInfo(val scope: DIScopeOpaqueRef,
|
||||
val line: Int,
|
||||
val column: Int) {
|
||||
init {
|
||||
assert(line != 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ const char* CSSourceInfoGetPath(CSSourceInfoRef info);
|
||||
const char* CSSourceInfoGetFilename(CSSourceInfoRef info);
|
||||
|
||||
uint32_t CSSourceInfoGetLineNumber(CSSourceInfoRef info);
|
||||
uint32_t CSSourceInfoGetColumn(CSSourceInfoRef info);
|
||||
|
||||
CSTypeRef CSRetain(CSTypeRef);
|
||||
|
||||
|
||||
@@ -21,6 +21,32 @@ fun archToCpuName(arch: String): cpu_type_t = when (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>) {
|
||||
val symbolicator = CSSymbolicatorCreateWithPathAndArchitecture(program, archToCpuName(arch))
|
||||
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)) {
|
||||
CSSymbolGetRange(symbol).useContents {
|
||||
val address = this.location + offsetInFunction
|
||||
val sourceInfo = CSSymbolOwnerGetSourceInfoWithAddress(owner, address)
|
||||
if (!CSIsNull(sourceInfo)) {
|
||||
val filePath = CSSourceInfoGetPath(sourceInfo)?.toKString()
|
||||
// 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")
|
||||
val sourceInfo = sourceInfoString(owner, address)
|
||||
if (sourceInfo != null) {
|
||||
result = matcher.replaceFirst(line, "$atPart$functionName $sourceInfo")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user