diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index bbc55032fa1..3c830867fee 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -734,7 +734,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState, private val scope by lazy { if (!context.shouldContainLocationDebugInfo() || declaration == null) return@lazy null - declaration.scope() ?: llvmFunction.scope(0, debugInfo.subroutineType(codegen.llvmTargetData, listOf(context.irBuiltIns.intType))) + declaration.scope() ?: llvmFunction.scope(0, debugInfo.subroutineType(codegen.llvmTargetData, listOf(context.irBuiltIns.intType)), false) } private val fileScope = (fileScope() as? FileScope) @@ -2189,11 +2189,13 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState, else -> codegen.llvmFunctionOrNull(this)?.llvmValue } return with(debugInfo) { + val f = this@scope + val nodebug = f is IrConstructor && f.parentAsClass.isSubclassOf(context.irBuiltIns.throwableClass.owner) if (functionLlvmValue != null) { subprograms.getOrPut(functionLlvmValue) { memScoped { val subroutineType = subroutineType(codegen.llvmTargetData) - diFunctionScope(name.asString(), functionLlvmValue.name!!, startLine, subroutineType).also { + diFunctionScope(name.asString(), functionLlvmValue.name!!, startLine, subroutineType, nodebug).also { if (!this@scope.isInline) DIFunctionAddSubprogram(functionLlvmValue, it) } @@ -2203,7 +2205,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState, inlinedSubprograms.getOrPut(this@scope) { memScoped { val subroutineType = subroutineType(codegen.llvmTargetData) - diFunctionScope(name.asString(), "", startLine, subroutineType) + diFunctionScope(name.asString(), "", startLine, subroutineType, nodebug) } } as DIScopeOpaqueRef } @@ -2212,19 +2214,19 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState, } @Suppress("UNCHECKED_CAST") - private fun LLVMValueRef.scope(startLine:Int, subroutineType: DISubroutineTypeRef): DIScopeOpaqueRef? { + private fun LLVMValueRef.scope(startLine:Int, subroutineType: DISubroutineTypeRef, nodebug: Boolean): DIScopeOpaqueRef? { return debugInfo.subprograms.getOrPut(this) { - diFunctionScope(name!!, name!!, startLine, subroutineType).also { + diFunctionScope(name!!, name!!, startLine, subroutineType, nodebug).also { DIFunctionAddSubprogram(this@scope, it) } } as DIScopeOpaqueRef } @Suppress("UNCHECKED_CAST") - private fun diFunctionScope(name: String, linkageName: String, startLine: Int, subroutineType: DISubroutineTypeRef) = DICreateFunction( + private fun diFunctionScope(name: String, linkageName: String, startLine: Int, subroutineType: DISubroutineTypeRef, nodebug: Boolean) = DICreateFunction( builder = debugInfo.builder, scope = debugInfo.compilationUnit, - name = name, + name = (if (nodebug) "" else "") + name, linkageName = linkageName, file = file().file(), lineNo = startLine, diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index ce0270dca1f..ebcffc3d6d7 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -2735,15 +2735,10 @@ task extend_exception(type: KonanLocalTest) { source = "runtime/exceptions/extend0.kt" } -standaloneTest("check_stacktrace_format") { - disabled = !supportsCoreSymbolication(project) || project.globalTestArgs.contains('-opt') - flags = ['-g'] - source = "runtime/exceptions/check_stacktrace_format.kt" -} - standaloneTest("check_stacktrace_format_coresymbolication") { disabled = !supportsCoreSymbolication(project) || project.globalTestArgs.contains('-opt') flags = ['-g', '-Xbinary=sourceInfoType=coresymbolication'] + arguments = ['coresymbolication'] source = "runtime/exceptions/check_stacktrace_format.kt" } @@ -2751,9 +2746,7 @@ standaloneTest("stack_trace_inline") { disabled = !supportsCoreSymbolication(project) || project.globalTestArgs.contains('-opt') flags = ['-g', '-Xg-generate-debug-trampoline=enable', '-Xbinary=sourceInfoType=coresymbolication'] source = "runtime/exceptions/stack_trace_inline.kt" - // test on simulator is writing Invalid connection: com.apple.coresymbolicationd by unknown reason - // so we need to use custom checker as workaround - outputChecker = { str -> str.split("\n").contains("0") } + arguments = ['coresymbolication'] } standaloneTest("kt-49240-stack-trace-completeness") { @@ -2771,30 +2764,41 @@ standaloneTest("stack_trace_out_of_bounds") { standaloneTest("kt-37572") { disabled = !supportsCoreSymbolication(project) || project.globalTestArgs.contains('-opt') flags = ['-g', '-Xbinary=sourceInfoType=coresymbolication'] + arguments = ['coresymbolication'] source = "runtime/exceptions/kt-37572.kt" - // test on simulator is writing Invalid connection: com.apple.coresymbolicationd by unknown reason - // so we need to use custom checker as workaround - outputChecker = { str -> str.split("\n").contains("0") } } standaloneTest("check_stacktrace_format_libbacktrace") { disabled = !supportsLibBacktrace(project)|| project.globalTestArgs.contains('-opt') flags = ['-g', '-Xbinary=sourceInfoType=libbacktrace'] + arguments = ['libbacktrace'] source = "runtime/exceptions/check_stacktrace_format.kt" } standaloneTest("stack_trace_inline_libbacktrace") { disabled = !supportsLibBacktrace(project) || project.globalTestArgs.contains('-opt') flags = ['-g', '-Xbinary=sourceInfoType=libbacktrace'] + arguments = ['libbacktrace'] source = "runtime/exceptions/stack_trace_inline.kt" - outputChecker = { str -> str.split("\n").contains("1") } } standaloneTest("kt-37572-libbacktrace") { disabled = !supportsLibBacktrace(project) || project.globalTestArgs.contains('-opt') flags = ['-g', '-Xbinary=sourceInfoType=libbacktrace'] + arguments = ['libbacktrace'] source = "runtime/exceptions/kt-37572.kt" - outputChecker = { str -> str.split("\n").contains("2") } +} + +standaloneTest("except_constr_w_default") { + disabled = !supportsLibBacktrace(project) || project.globalTestArgs.contains('-opt') + flags = ['-g', '-Xbinary=sourceInfoType=libbacktrace'] + source = "runtime/exceptions/except_constr_w_default.kt" +} + +standaloneTest("throw_from_except_constr") { + disabled = !supportsLibBacktrace(project) || project.globalTestArgs.contains('-opt') + flags = ['-g', '-Xbinary=sourceInfoType=libbacktrace'] + source = "runtime/exceptions/throw_from_except_constr.kt" } standaloneTest("custom_hook") { diff --git a/kotlin-native/backend.native/tests/framework/stacktraceByLibbacktrace/stacktraceByLibbacktrace.swift b/kotlin-native/backend.native/tests/framework/stacktraceByLibbacktrace/stacktraceByLibbacktrace.swift index 03221b13cd0..8343c48f979 100644 --- a/kotlin-native/backend.native/tests/framework/stacktraceByLibbacktrace/stacktraceByLibbacktrace.swift +++ b/kotlin-native/backend.native/tests/framework/stacktraceByLibbacktrace/stacktraceByLibbacktrace.swift @@ -3,15 +3,13 @@ import StacktraceByLibbacktrace func testStackTrace() throws { let trace = StacktraceByLibbacktraceKt.getStackTrace() - try assertTrue(trace[0].contains("Throwable.kt")) - try assertTrue(trace[1].contains("Exceptions.kt")) - try assertTrue(trace[2].contains("stacktraceByLibbacktrace.kt:7")) - try assertTrue(trace[2].contains("[inlined]")) - try assertTrue(trace[3].contains("stacktraceByLibbacktrace.kt:11")) - try assertTrue(trace[4].contains("stacktraceByLibbacktrace.kt:16")) - try assertTrue(trace[5].contains("")) - try assertTrue(trace[6].contains("stacktraceByLibbacktrace.swift:5")) - try assertTrue(trace[7].contains("main.swift:126")) + try assertTrue(trace[0].contains("stacktraceByLibbacktrace.kt:7")) + try assertTrue(trace[0].contains("[inlined]")) + try assertTrue(trace[1].contains("stacktraceByLibbacktrace.kt:11")) + try assertTrue(trace[2].contains("stacktraceByLibbacktrace.kt:16")) + try assertTrue(trace[3].contains("")) + try assertTrue(trace[4].contains("stacktraceByLibbacktrace.swift:5")) + try assertTrue(trace[5].contains("main.swift:126")) } class StacktraceByLibbacktraceTests : TestProvider { diff --git a/kotlin-native/backend.native/tests/runtime/exceptions/check_stacktrace_format.kt b/kotlin-native/backend.native/tests/runtime/exceptions/check_stacktrace_format.kt index 2f21dc84d64..19ce86f2019 100644 --- a/kotlin-native/backend.native/tests/runtime/exceptions/check_stacktrace_format.kt +++ b/kotlin-native/backend.native/tests/runtime/exceptions/check_stacktrace_format.kt @@ -29,9 +29,16 @@ fun functionB() { functionA() } -const val depth = 5 +var depth = 3 fun main(args : Array) { + val sourceInfoType = args.first() + val exceptionalFrames = when (sourceInfoType) { + "libbacktrace" -> 0 + "coresymbolication" -> 2 + else -> throw AssertionError("Unknown source info type " + sourceInfoType) + } + depth += exceptionalFrames try { functionB() } catch (e: Throwable) { diff --git a/kotlin-native/backend.native/tests/runtime/exceptions/except_constr_w_default.kt b/kotlin-native/backend.native/tests/runtime/exceptions/except_constr_w_default.kt new file mode 100644 index 00000000000..e07d0b9b243 --- /dev/null +++ b/kotlin-native/backend.native/tests/runtime/exceptions/except_constr_w_default.kt @@ -0,0 +1,38 @@ +import kotlin.text.Regex +import kotlin.test.* + +class CustomException(msg: String = "Exceptional message") : Exception(msg) { +} + +fun exception() { + throw CustomException() +} + +fun main() { + try { + exception() + } + catch (e:Exception) { + val stackTrace = e.getStackTrace().filter { "kfun:" in it } + println("Kotlin part of call stack is:") + for (entry in stackTrace) + println(entry) + println("Verifying...") + val goldValues = arrayOf( + "kfun:#exception(){}", + "kfun:#main(){}", + ) + assertEquals(goldValues.size, stackTrace.size) + goldValues.zip(stackTrace).forEach { checkFrame(it.first, it.second) } + println("Passed") + } +} + +internal val regex = Regex("(kfun.+) \\+ (\\d+)") +internal fun checkFrame(goldFunName: String, actualLine: String) { + val findResult = regex.find(actualLine) + + val (funName, offset) = findResult?.destructured ?: throw Error("Cannot find '$goldFunName + ' in $actualLine") + assertEquals(goldFunName, funName) + assertTrue(offset.toInt() > 0) +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/exceptions/kt-37572.kt b/kotlin-native/backend.native/tests/runtime/exceptions/kt-37572.kt index 01d2b05ac70..aa8f6deef1d 100644 --- a/kotlin-native/backend.native/tests/runtime/exceptions/kt-37572.kt +++ b/kotlin-native/backend.native/tests/runtime/exceptions/kt-37572.kt @@ -1,17 +1,28 @@ import kotlin.text.Regex import kotlin.test.* -var inlinesCount = 0 +var expectedInlinesCount = 0 +var expectedExceptionContrFrames = 0 -fun main() { +fun main(args: Array) { + val sourceInfoType = args.first() + val (e, i) = when (sourceInfoType) { + "libbacktrace" -> Pair(0, 2) + "coresymbolication" -> Pair(2, 0) + else -> throw AssertionError("Unknown source info type " + sourceInfoType) + } + expectedExceptionContrFrames = e + expectedInlinesCount = i + + var actualInlinesCount = 0 try { foo() } catch (tw:Throwable) { val stackTrace = tw.getStackTrace(); - inlinesCount = stackTrace.count { it.contains("[inlined]")} - stackTrace.take(6).forEach(::checkFrame) + actualInlinesCount = stackTrace.count { it.contains("[inlined]")} + stackTrace.take(expectedExceptionContrFrames + 4).forEach(::checkFrame) } - println(inlinesCount) + assertEquals(expectedInlinesCount, actualInlinesCount) } fun foo() { @@ -32,16 +43,15 @@ internal val regex = Regex("^(\\d+)\\ +.*/(.*):(\\d+):.*$") internal fun checkFrame(value:String) { val goldValues = arrayOf?>( - null, - null, - "kt-37572.kt" to 29, - "kt-37572.kt" to 20, - *(if (inlinesCount != 0) arrayOf( - "kt-37572.kt" to 25, - "kt-37572.kt" to 18, + *arrayOfNulls(expectedExceptionContrFrames), + "kt-37572.kt" to 40, + "kt-37572.kt" to 31, + *(if (expectedInlinesCount != 0) arrayOf( + "kt-37572.kt" to 36, + "kt-37572.kt" to 29, ) else emptyArray()), - "kt-37572.kt" to 8, - "kt-37572.kt" to 6) + "kt-37572.kt" to 19, + "kt-37572.kt" to 7) val (pos, file, line) = regex.find(value)!!.destructured goldValues[pos.toInt()]?.let { diff --git a/kotlin-native/backend.native/tests/runtime/exceptions/stack_trace_inline.kt b/kotlin-native/backend.native/tests/runtime/exceptions/stack_trace_inline.kt index 1b558c96425..e41137dcd82 100644 --- a/kotlin-native/backend.native/tests/runtime/exceptions/stack_trace_inline.kt +++ b/kotlin-native/backend.native/tests/runtime/exceptions/stack_trace_inline.kt @@ -1,33 +1,41 @@ import kotlin.text.Regex import kotlin.test.* -var inlinesCount = 0 +var expectedInlinesCount = 0 +var expectedExceptionContrFrames = 0 fun exception() { error("FAIL!") } -fun main() { +fun main(args: Array) { + val sourceInfoType = args.first() + val (e, i) = when (sourceInfoType) { + "libbacktrace" -> Pair(0, 1) + "coresymbolication" -> Pair(4, 0) + else -> throw AssertionError("Unknown source info type " + sourceInfoType) + } + expectedExceptionContrFrames = e + expectedInlinesCount = i + + var actualInlinesCount = 0 try { exception() } catch (e:Exception) { val stackTrace = e.getStackTrace() - inlinesCount = stackTrace.count { it.contains("[inlined]")} - stackTrace.take(6).forEach(::checkFrame) + actualInlinesCount = stackTrace.count { it.contains("[inlined]")} + stackTrace.take(expectedExceptionContrFrames + 2).forEach(::checkFrame) } - println(inlinesCount) + assertEquals(expectedInlinesCount, actualInlinesCount) } internal val regex = Regex("^(\\d+)\\ +.*/(.*):(\\d+):.*$") internal fun checkFrame(value:String) { val goldValues = arrayOf?>( - null, - null, - null, - null, - *(if (inlinesCount != 0) arrayOf(null) else emptyArray()), - "stack_trace_inline.kt" to 7, - "stack_trace_inline.kt" to 12) + *arrayOfNulls(expectedExceptionContrFrames), + *arrayOfNulls(expectedInlinesCount), + "stack_trace_inline.kt" to 8, + "stack_trace_inline.kt" to 23) val (pos, file, line) = regex.find(value)!!.destructured goldValues[pos.toInt()]?.let { assertEquals(it.first, file) diff --git a/kotlin-native/backend.native/tests/runtime/exceptions/throw_from_except_constr.kt b/kotlin-native/backend.native/tests/runtime/exceptions/throw_from_except_constr.kt new file mode 100644 index 00000000000..9c875d1e057 --- /dev/null +++ b/kotlin-native/backend.native/tests/runtime/exceptions/throw_from_except_constr.kt @@ -0,0 +1,46 @@ +import kotlin.text.Regex +import kotlin.test.* + +class CustomException(msg: String) : Exception(msg) { + init { + constrException() + } + + fun constrException() { + throw Exception("Exception during exception's construction") + } +} + +fun exception() { + throw CustomException("Exceptional message") +} + +fun main() { + try { + exception() + } + catch (e:Exception) { + val stackTrace = e.getStackTrace().filter { "kfun:" in it } + println("Kotlin part of call stack is:") + for (entry in stackTrace) + println(entry) + println("Verifying...") + val goldValues = arrayOf( + "kfun:CustomException#constrException(){}", + "kfun:#exception(){}", + "kfun:#main(){}", + ) + assertEquals(goldValues.size, stackTrace.size) + goldValues.zip(stackTrace).forEach { checkFrame(it.first, it.second) } + println("Passed") + } +} + +internal val regex = Regex("(kfun.+) \\+ (\\d+)") +internal fun checkFrame(goldFunName: String, actualLine: String) { + val findResult = regex.find(actualLine) + + val (funName, offset) = findResult?.destructured ?: throw Error("Cannot find '$goldFunName + ' in $actualLine") + assertEquals(goldFunName, funName) + assertTrue(offset.toInt() > 0) +} \ No newline at end of file diff --git a/kotlin-native/runtime/src/libbacktrace/c/backtrace.c b/kotlin-native/runtime/src/libbacktrace/c/backtrace.c index 0c46fc5b6b6..2d093fe7cf0 100644 --- a/kotlin-native/runtime/src/libbacktrace/c/backtrace.c +++ b/kotlin-native/runtime/src/libbacktrace/c/backtrace.c @@ -86,7 +86,7 @@ unwind (struct _Unwind_Context *context, void *vdata) --pc; if (!bdata->can_alloc) - bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, 0, NULL); + bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, 0, NULL, 0); else bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback, bdata->error_callback, bdata->data); diff --git a/kotlin-native/runtime/src/libbacktrace/c/dwarf.c b/kotlin-native/runtime/src/libbacktrace/c/dwarf.c index 95192443393..94e62aac680 100644 --- a/kotlin-native/runtime/src/libbacktrace/c/dwarf.c +++ b/kotlin-native/runtime/src/libbacktrace/c/dwarf.c @@ -376,6 +376,8 @@ enum dwarf_unit_type { DW_UT_hi_user = 0xff }; +const char * const KN_nodebug_prefix = ""; + #if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN /* If strnlen is not declared, provide our own version. */ @@ -601,6 +603,8 @@ struct function /* If this is an inlined function, the column of the call site. */ int caller_column; + /* Whether the funciton should be hidden from user-level debug output (e.g. from Kotlin stack traces). */ + int is_nodebug; /* Map PC ranges to inlined functions. */ struct function_addrs *function_addrs; size_t function_addrs_count; @@ -3675,15 +3679,22 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, case DW_AT_name: /* Third name preference: don't override. */ - if (function->name != NULL) + { + const char *n = NULL; + if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, + ddata->is_bigendian, + u->str_offsets_base, &val, + error_callback, data, &n)) + return 0; + if (n != NULL) { + if (function->name == NULL) + function->name = n; + /* nodebug prefix may not be mangled in other name variants */ + if (strncmp(n, KN_nodebug_prefix, strlen(KN_nodebug_prefix)) == 0) + function->is_nodebug = 1; + } break; - if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64, - ddata->is_bigendian, - u->str_offsets_base, &val, - error_callback, data, &function->name)) - return 0; - break; - + } case DW_AT_linkage_name: case DW_AT_MIPS_linkage_name: /* First name preference: override all. */ @@ -3954,7 +3965,7 @@ report_inlined_functions (uintptr_t pc, struct function *function, return ret; /* Report this inlined call. */ - ret = callback (data, pc, *filename, *lineno, *column, inlined->name); + ret = callback (data, pc, *filename, *lineno, *column, inlined->name, inlined->is_nodebug); if (ret != 0) return ret; @@ -4131,7 +4142,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, if (new_data) return dwarf_lookup_pc (state, ddata, pc, callback, error_callback, data, found); - return callback (data, pc, NULL, 0, 0, NULL); + return callback (data, pc, NULL, 0, 0, NULL, 0); } /* Search for PC within this unit. */ @@ -4178,13 +4189,13 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, entry->u->abs_filename = filename; } - return callback (data, pc, entry->u->abs_filename, 0, 0, NULL); + return callback (data, pc, entry->u->abs_filename, 0, 0, NULL, 0); } /* Search for function name within this unit. */ if (entry->u->function_addrs_count == 0) - return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL); + return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL, 0); p = ((struct function_addrs *) bsearch (&pc, entry->u->function_addrs, @@ -4192,7 +4203,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, sizeof (struct function_addrs), function_addrs_search)); if (p == NULL) - return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL); + return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL, 0); /* Here pc >= p->low && pc < (p + 1)->low. The function_addrs are sorted by low, so if pc > p->low we are at the end of a range of @@ -4216,7 +4227,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, --p; } if (fmatch == NULL) - return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL); + return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL, 0); function = fmatch->function; @@ -4229,7 +4240,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, if (ret != 0) return ret; - return callback (data, pc, filename, lineno, column, function->name); + return callback (data, pc, filename, lineno, column, function->name, function->is_nodebug); } @@ -4279,7 +4290,7 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc, /* FIXME: See if any libraries have been dlopen'ed. */ - return callback (data, pc, NULL, 0, 0, NULL); + return callback (data, pc, NULL, 0, 0, NULL, 0); } /* Initialize our data structures from the DWARF debug info for a diff --git a/kotlin-native/runtime/src/libbacktrace/c/fileline.c b/kotlin-native/runtime/src/libbacktrace/c/fileline.c index 0a6c60f1444..264e445939c 100644 --- a/kotlin-native/runtime/src/libbacktrace/c/fileline.c +++ b/kotlin-native/runtime/src/libbacktrace/c/fileline.c @@ -330,7 +330,7 @@ backtrace_syminfo_to_full_callback (void *data, uintptr_t pc, { struct backtrace_call_full *bdata = (struct backtrace_call_full *) data; - bdata->ret = bdata->full_callback (bdata->full_data, pc, NULL, 0, 0, symname); + bdata->ret = bdata->full_callback (bdata->full_data, pc, NULL, 0, 0, symname, 0); } /* An error callback that corresponds to diff --git a/kotlin-native/runtime/src/libbacktrace/c/include/backtrace.h b/kotlin-native/runtime/src/libbacktrace/c/include/backtrace.h index 16f21a242b2..ccaffaaf468 100644 --- a/kotlin-native/runtime/src/libbacktrace/c/include/backtrace.h +++ b/kotlin-native/runtime/src/libbacktrace/c/include/backtrace.h @@ -99,7 +99,7 @@ extern struct backtrace_state *backtrace_create_state ( typedef int (*backtrace_full_callback) (void *data, uintptr_t pc, const char *filename, int lineno, int column, - const char *function); + const char *function, int is_nodebug); /* Get a full stack backtrace. SKIP is the number of frames to skip; passing 0 will start the trace with the function calling diff --git a/kotlin-native/runtime/src/libbacktrace/c/print.c b/kotlin-native/runtime/src/libbacktrace/c/print.c index 5fbc43b9d26..ceb178933a3 100644 --- a/kotlin-native/runtime/src/libbacktrace/c/print.c +++ b/kotlin-native/runtime/src/libbacktrace/c/print.c @@ -51,15 +51,16 @@ struct print_data static int print_callback (void *data, uintptr_t pc, const char *filename, int lineno, int column, - const char *function) + const char *function, int is_nodebug) { - struct print_data *pdata = (struct print_data *) data; - - fprintf (pdata->f, "0x%lx %s\n\t%s:%d:%d\n", - (unsigned long) pc, - function == NULL ? "???" : function, - filename == NULL ? "???" : filename, - lineno, column); + if (!is_nodebug) { + struct print_data *pdata = (struct print_data *) data; + fprintf (pdata->f, "0x%lx %s\n\t%s:%d:%d\n", + (unsigned long) pc, + function == NULL ? "???" : function, + filename == NULL ? "???" : filename, + lineno, column); + } return 0; } diff --git a/kotlin-native/runtime/src/main/cpp/SourceInfo.h b/kotlin-native/runtime/src/main/cpp/SourceInfo.h index 8d302be7c5c..cb88b3a3224 100644 --- a/kotlin-native/runtime/src/main/cpp/SourceInfo.h +++ b/kotlin-native/runtime/src/main/cpp/SourceInfo.h @@ -24,6 +24,7 @@ class SourceInfo { public: int lineNumber = -1; int column = -1; + bool nodebug = false; std::string& getFileName() { return fileName; } void setFilename(const char *newFileName) { fileName = newFileName ?: ""; } }; diff --git a/kotlin-native/runtime/src/main/cpp/StackTrace.cpp b/kotlin-native/runtime/src/main/cpp/StackTrace.cpp index f107d55814f..cc3f0d73c2b 100644 --- a/kotlin-native/runtime/src/main/cpp/StackTrace.cpp +++ b/kotlin-native/runtime/src/main/cpp/StackTrace.cpp @@ -294,10 +294,13 @@ std_support::vector kotlin::GetStackTraceStrings(std_suppor int frames_or_overflow = getSourceInfo(address, buffer, std::size(buffer)); int frames = std::min(frames_or_overflow, std::size(buffer)); bool isSomethingPrinted = false; + bool isSomethingHidden = false; char line[1024]; for (int frame = 0; frame < frames; frame++) { auto &sourceInfo = buffer[frame]; - if (!sourceInfo.getFileName().empty()) { + if (sourceInfo.nodebug) { + isSomethingHidden = true; + } else if (!sourceInfo.getFileName().empty()) { bool is_last = frame == frames - 1; if (is_last && frames_or_overflow != frames) { snprintf_with_addr(line, sizeof(line) - 1, strings.size(), address, false, "[some inlined frames skipped]"); @@ -322,7 +325,7 @@ std_support::vector kotlin::GetStackTraceStrings(std_suppor strings.push_back(line); } } - if (!isSomethingPrinted) { + if (!isSomethingPrinted && !isSomethingHidden) { snprintf_with_addr(line, sizeof(line) - 1, strings.size(), address, false, "%s", ""); strings.push_back(line); } diff --git a/kotlin-native/runtime/src/source_info/libbacktrace/cpp/SourceInfo.cpp b/kotlin-native/runtime/src/source_info/libbacktrace/cpp/SourceInfo.cpp index 41a0c3780f3..1dd9fd52f71 100644 --- a/kotlin-native/runtime/src/source_info/libbacktrace/cpp/SourceInfo.cpp +++ b/kotlin-native/runtime/src/source_info/libbacktrace/cpp/SourceInfo.cpp @@ -23,7 +23,7 @@ extern "C" int Kotlin_getSourceInfo_libbacktrace(void* addr, SourceInfo *result, callback_arg.result_ptr = 0; callback_arg.result_size = result_size; callback_arg.total_count = 0; - auto process_line = [](void *data, uintptr_t pc, const char *filename, int lineno, int column, const char *function) -> int { + auto process_line = [](void *data, uintptr_t pc, const char *filename, int lineno, int column, const char *function, int is_nodebug) -> int { auto &callback_arg = *static_cast(data); // Non-inlined frame would be last one, it's better to have it, then intermediate ones if (callback_arg.result_ptr == callback_arg.result_size) { @@ -33,6 +33,7 @@ extern "C" int Kotlin_getSourceInfo_libbacktrace(void* addr, SourceInfo *result, info.setFilename(filename); info.lineNumber = lineno; info.column = column; + info.nodebug = is_nodebug; callback_arg.result_ptr++; callback_arg.total_count++; // Let's stop at least at some point