Add line numbers to stacktraces in macos_x64/ios_x64 debug binaries (#2489)
This commit is contained in:
committed by
Nikolay Igotti
parent
7de47bb1de
commit
cfd6b80e6a
+1
-1
@@ -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)
|
||||
|
||||
|
||||
+20
-4
@@ -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)!!
|
||||
|
||||
|
||||
+3
-2
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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) =
|
||||
|
||||
Reference in New Issue
Block a user