Improve symbolicator, generate better debug info (#2488)

This commit is contained in:
Nikolay Igotti
2018-12-21 18:20:53 +03:00
committed by GitHub
parent f78e80ceda
commit 4d6fb2926d
4 changed files with 55 additions and 26 deletions
@@ -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) {
@@ -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")
}
}
}