Add line numbers to stacktraces in macos_x64/ios_x64 debug binaries (#2489)

This commit is contained in:
SvyatoslavScherbina
2018-12-24 17:05:27 +03:00
committed by Nikolay Igotti
parent 7de47bb1de
commit cfd6b80e6a
13 changed files with 258 additions and 16 deletions
@@ -496,7 +496,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
fun shouldProfilePhases() = config.configuration.getBoolean(KonanConfigKeys.TIME_PHASES)
fun shouldContainDebugInfo() = config.configuration.getBoolean(KonanConfigKeys.DEBUG)
fun shouldContainDebugInfo() = config.debug
fun shouldOptimize() = config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION)
@@ -41,6 +41,8 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
val infoArgsOnly = configuration.kotlinSourceRoots.isEmpty() && !linkOnly
val debug: Boolean get() = configuration.getBoolean(KonanConfigKeys.DEBUG)
init {
if (!platformManager.isEnabled(target)) {
error("Target ${target.visibleName} is not available on the ${HostManager.hostName} host")
@@ -106,10 +108,14 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
return resolvedLibraries.filterRoots { (!it.isDefault && !this.purgeUserLibs) || it.isNeededForLink }.getFullList()
}
internal val defaultNativeLibraries =
if (produce == CompilerOutputKind.PROGRAM)
File(distribution.defaultNatives(target)).listFiles.map { it.absolutePath }
else emptyList()
internal val defaultNativeLibraries: List<String> = mutableListOf<String>().apply {
add(if (debug) "debug.bc" else "release.bc")
if (produce == CompilerOutputKind.PROGRAM) {
addAll(distribution.launcherFiles)
}
}.map {
File(distribution.defaultNatives(target)).child(it).absolutePath
}
internal val nativeLibraries: List<String> =
configuration.getList(KonanConfigKeys.NATIVE_LIBRARY_FILES)
@@ -117,6 +123,16 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
internal val includeBinaries: List<String> =
configuration.getList(KonanConfigKeys.INCLUDED_BINARY_FILES)
internal val defaultSystemLibraries: List<String> = when (target) {
KonanTarget.MACOS_X64, KonanTarget.IOS_X64 -> if (debug) {
listOf(File(distribution.tbdDirectory(target)).child("CoreSymbolication.tbd").absolutePath)
} else {
emptyList()
}
else -> emptyList()
}
internal val languageVersionSettings =
configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)!!
@@ -23,7 +23,7 @@ internal class LinkStage(val context: Context, val phaser: PhaseManager) {
private val linker = platform.linker
private val optimize = context.shouldOptimize()
private val debug = config.get(KonanConfigKeys.DEBUG) ?: false
private val debug = context.config.debug
private val linkerOutput = when (context.config.produce) {
CompilerOutputKind.DYNAMIC, CompilerOutputKind.FRAMEWORK -> LinkerOutputKind.DYNAMIC_LIBRARY
CompilerOutputKind.STATIC -> LinkerOutputKind.STATIC_LIBRARY
@@ -181,7 +181,8 @@ internal class LinkStage(val context: Context, val phaser: PhaseManager) {
try {
File(executable).delete()
linker.linkCommands(objectFiles = objectFiles, executable = executable,
libraries = linker.targetLibffi + linker.linkStaticLibraries(includedBinaries),
libraries = linker.targetLibffi + linker.linkStaticLibraries(includedBinaries) +
context.config.defaultSystemLibraries,
linkerArgs = entryPointSelector +
asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) +
BitcodeEmbedding.getLinkerOptions(context.config) +
@@ -0,0 +1,16 @@
--- !tapi-tbd-v3
archs: [ x86_64 ]
uuids: [ 'x86_64: BA456C79-974B-499E-9013-BEDB414FE7B9' ]
platform: ios
install-name: /System/Library/PrivateFrameworks/CoreSymbolication.framework/CoreSymbolication
exports:
- archs: [ x86_64 ]
symbols: [ _CSIsNull,
_CSSourceInfoGetFilename,
_CSSourceInfoGetPath,
_CSSourceInfoGetLineNumber,
_CSSourceInfoGetColumn,
_CSSymbolOwnerGetSourceInfoWithAddress,
_CSSymbolicatorCreateWithPid,
_CSSymbolicatorGetSymbolOwnerWithAddressAtTime ]
...
@@ -0,0 +1,16 @@
--- !tapi-tbd-v3
archs: [ x86_64 ]
uuids: [ 'x86_64: E996B8F6-929B-4111-A859-EB054C062FE8' ]
platform: macosx
install-name: /System/Library/PrivateFrameworks/CoreSymbolication.framework/Versions/A/CoreSymbolication
exports:
- archs: [ x86_64 ]
symbols: [ _CSIsNull,
_CSSourceInfoGetFilename,
_CSSourceInfoGetPath,
_CSSourceInfoGetLineNumber,
_CSSourceInfoGetColumn,
_CSSymbolOwnerGetSourceInfoWithAddress,
_CSSymbolicatorCreateWithPid,
_CSSymbolicatorGetSymbolOwnerWithAddressAtTime ]
...
+23 -6
View File
@@ -6,30 +6,47 @@ import org.jetbrains.kotlin.CompileCppToBitcode
// TODO: consider using some Gradle plugins to build and test
void includeRuntime(CompileCppToBitcode task) {
task.compilerArgs '-I' + project.file('../common/src/hash/headers')
task.compilerArgs '-I' + project.file('src/main/cpp')
}
targetList.each { targetName ->
task("${targetName}Runtime", type: CompileCppToBitcode) {
name "runtime"
srcRoot file('src/main')
dependsOn ":common:${targetName}Hash"
dependsOn "${targetName}Launcher"
dependsOn "${targetName}Debug"
dependsOn "${targetName}Release"
target targetName
if (!isWindows())
compilerArgs '-fPIC'
compilerArgs '-I' + project.file('../common/src/hash/headers')
compilerArgs '-I' + file('src/main/cpp')
includeRuntime(delegate)
if (rootProject.hasProperty("${targetName}LibffiDir"))
compilerArgs '-I' + project.file(rootProject.ext.get("${targetName}LibffiDir") + "/include")
linkerArgs project.file("../common/build/$targetName/hash.bc").path
}
}
targetList.each { targetName ->
task("${targetName}Launcher", type: CompileCppToBitcode) {
name "launcher"
srcRoot file('src/launcher')
target targetName
compilerArgs '-I' + project.file('../common/src/hash/headers')
compilerArgs '-I' + project.file('src/main/cpp')
includeRuntime(delegate)
}
task ("${targetName}Debug", type: CompileCppToBitcode) {
name "debug"
srcRoot file('src/debug')
target targetName
includeRuntime(delegate)
}
task ("${targetName}Release", type: CompileCppToBitcode) {
name "release"
srcRoot file('src/release')
target targetName
includeRuntime(delegate)
}
}
+103
View File
@@ -0,0 +1,103 @@
/*
* Copyright 2010-2018 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.
*/
#include "SourceInfo.h"
#ifdef KONAN_CORE_SYMBOLICATION
#include <limits.h>
#include <stdint.h>
#include <unistd.h>
typedef struct _CSTypeRef {
unsigned long type;
void* contents;
} CSTypeRef;
typedef CSTypeRef CSSymbolicatorRef;
typedef CSTypeRef CSSymbolOwnerRef;
typedef CSTypeRef CSSymbolRef;
typedef CSTypeRef CSSourceInfoRef;
typedef struct _CSRange {
unsigned long long location;
unsigned long long length;
} CSRange;
typedef unsigned long long CSArchitecture;
#define kCSNow LONG_MAX
extern "C" {
CSSymbolicatorRef CSSymbolicatorCreateWithPid(pid_t pid);
CSSymbolOwnerRef CSSymbolicatorGetSymbolOwnerWithAddressAtTime(
CSSymbolicatorRef symbolicator,
unsigned long long address,
long time
);
CSSourceInfoRef CSSymbolOwnerGetSourceInfoWithAddress(
CSSymbolOwnerRef owner,
unsigned long long address
);
const char* CSSourceInfoGetPath(CSSourceInfoRef info);
uint32_t CSSourceInfoGetLineNumber(CSSourceInfoRef info);
uint32_t CSSourceInfoGetColumn(CSSourceInfoRef info);
bool CSIsNull(CSTypeRef);
} // extern "C"
extern "C" struct SourceInfo Kotlin_getSourceInfo(void* addr) {
SourceInfo result = { .fileName = nullptr, .lineNumber = -1, .column = -1 };
static CSSymbolicatorRef symbolicator = CSSymbolicatorCreateWithPid(getpid());
if (!CSIsNull(symbolicator)) {
unsigned long long address = static_cast<unsigned long long>((uintptr_t)addr);
CSSymbolOwnerRef symbolOwner = CSSymbolicatorGetSymbolOwnerWithAddressAtTime(symbolicator, address, kCSNow);
CSSourceInfoRef sourceInfo = CSSymbolOwnerGetSourceInfoWithAddress(symbolOwner, address);
if (!CSIsNull(sourceInfo)) {
const char* fileName = CSSourceInfoGetPath(sourceInfo);
if (fileName != nullptr) {
result.fileName = fileName;
uint32_t lineNumber = CSSourceInfoGetLineNumber(sourceInfo);
if (lineNumber != 0) {
result.lineNumber = lineNumber;
result.column = CSSourceInfoGetColumn(sourceInfo);
}
}
}
}
return result;
}
#else // KONAN_CORE_SYMBOLICATION
extern "C" struct SourceInfo Kotlin_getSourceInfo(void* addr) {
return (SourceInfo) { .fileName = nullptr, .lineNumber = -1, .column = -1 };
}
#endif // KONAN_CORE_SYMBOLICATION
+17 -1
View File
@@ -39,6 +39,7 @@
#include "Memory.h"
#include "Natives.h"
#include "KString.h"
#include "SourceInfo.h"
#include "Types.h"
#include "Utils.h"
@@ -171,7 +172,22 @@ OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace) {
RuntimeCheck(symbols != nullptr, "Not enough memory to retrieve the stacktrace");
AutoFree autoFree(symbols);
for (int index = 0; index < size; ++index) {
CreateStringFromCString(symbols[index], ArrayAddressOfElementAt(strings->array(), index));
auto sourceInfo = Kotlin_getSourceInfo(*PrimitiveArrayAddressOfElementAt<KNativePtr>(stackTrace->array(), index));
const char* symbol = symbols[index];
const char* result;
char line[1024];
if (sourceInfo.fileName != nullptr) {
if (sourceInfo.lineNumber != -1) {
konan::snprintf(line, sizeof(line) - 1, "%s (%s:%d:%d)",
symbol, sourceInfo.fileName, sourceInfo.lineNumber, sourceInfo.column);
} else {
konan::snprintf(line, sizeof(line) - 1, "%s (%s:<unknown>)", symbol, sourceInfo.fileName);
}
result = line;
} else {
result = symbol;
}
CreateStringFromCString(result, ArrayAddressOfElementAt(strings->array(), index));
}
}
#endif
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2018 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.
*/
struct SourceInfo {
const char* fileName;
int lineNumber;
int column;
};
#ifdef __cplusplus
extern "C" {
#endif
struct SourceInfo Kotlin_getSourceInfo(void* addr);
#ifdef __cplusplus
} // extern "C"
#endif
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2018 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.
*/
#include "SourceInfo.h"
extern "C" struct SourceInfo Kotlin_getSourceInfo(void* addr) {
return (SourceInfo) { .fileName = nullptr, .lineNumber = -1, .column = -1 };
}
@@ -44,7 +44,7 @@ fun sourceInfoString(owner: CValue<CSSymbolOwnerRef>, address: ULong): String? {
if (sourceInfo == null) return null
val filePath = CSSourceInfoGetPath(sourceInfo)?.toKString() ?: return null
val columnNumber = CSSourceInfoGetColumn(sourceInfo)
return "$filePath:${if (maybe) "~" else ""}$lineNumber:$columnNumber"
return "$filePath:${if (lineNumber == 0u) "<unknown>" else "${if (maybe) "~" else ""}$lineNumber:$columnNumber"}"
}
fun analyzeTrace(program: String, arch: String, input: Sequence<String>) {
@@ -67,7 +67,7 @@ fun analyzeTrace(program: String, arch: String, input: Sequence<String>) {
val address = this.location + offsetInFunction
val sourceInfo = sourceInfoString(owner, address)
if (sourceInfo != null) {
result = matcher.replaceFirst(line, "$atPart$functionName $sourceInfo")
result = matcher.replaceFirst(line, "$atPart$functionName + $offsetInFunction ($sourceInfo)")
}
}
}
@@ -150,6 +150,7 @@ class ClangArgs(private val configurables: Configurables) : Configurables by con
KonanTarget.MACOS_X64 ->
listOf("-DKONAN_OSX=1",
"-DKONAN_OBJC_INTEROP=1",
"-DKONAN_CORE_SYMBOLICATION=1",
"-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1")
KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64 ->
@@ -158,6 +159,7 @@ class ClangArgs(private val configurables: Configurables) : Configurables by con
KonanTarget.IOS_X64 ->
listOf("-DKONAN_OBJC_INTEROP=1",
"-DKONAN_CORE_SYMBOLICATION=1",
"-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1")
KonanTarget.ANDROID_ARM32 ->
@@ -75,9 +75,12 @@ class Distribution(
val stdlib = "$klib/common/stdlib"
fun defaultNatives(target: KonanTarget) = "$konanHome/konan/targets/${target.visibleName}/native"
fun tbdDirectory(target: KonanTarget) = "$konanHome/konan/targets/${target.visibleName}/tbd"
fun runtime(target: KonanTarget) = runtimeFileOverride ?: "$stdlib/targets/${target.visibleName}/native/runtime.bc"
val launcherFiles = listOf("start.bc", "launcher.bc")
val dependenciesDir = DependencyProcessor.defaultDependenciesRoot.absolutePath
fun availableSubTarget(genericName: String) =