Symbolication sample (#2479)
This commit is contained in:
@@ -112,7 +112,6 @@ extern "C" int rpl_vsnprintf(char *, size_t, const char *, va_list);
|
|||||||
#define vsnprintf_impl ::vsnprintf
|
#define vsnprintf_impl ::vsnprintf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void consolePrintf(const char* format, ...) {
|
void consolePrintf(const char* format, ...) {
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
va_list args;
|
va_list args;
|
||||||
@@ -122,7 +121,6 @@ void consolePrintf(const char* format, ...) {
|
|||||||
consoleWriteUtf8(buffer, rv);
|
consoleWriteUtf8(buffer, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Thread execution.
|
// Thread execution.
|
||||||
#if !KONAN_NO_THREADS
|
#if !KONAN_NO_THREADS
|
||||||
|
|
||||||
@@ -325,7 +323,7 @@ void* moreCore(int32_t delta) {
|
|||||||
return (void *) top;
|
return (void *) top;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dlmalloc wants to know the page size.
|
// dlmalloc() wants to know the page size.
|
||||||
long getpagesize() {
|
long getpagesize() {
|
||||||
return WASM_PAGESIZE;
|
return WASM_PAGESIZE;
|
||||||
}
|
}
|
||||||
@@ -455,4 +453,5 @@ extern "C" {
|
|||||||
while(1) {}
|
while(1) {}
|
||||||
}
|
}
|
||||||
#endif // KONAN_ZEPHYR
|
#endif // KONAN_ZEPHYR
|
||||||
}
|
|
||||||
|
} // extern "C"
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ RuntimeState* initRuntime() {
|
|||||||
if (firstRuntime) {
|
if (firstRuntime) {
|
||||||
isMainThread = 1;
|
isMainThread = 1;
|
||||||
konan::consoleInit();
|
konan::consoleInit();
|
||||||
|
|
||||||
InitOrDeinitGlobalVariables(INIT_GLOBALS);
|
InitOrDeinitGlobalVariables(INIT_GLOBALS);
|
||||||
}
|
}
|
||||||
InitOrDeinitGlobalVariables(INIT_THREAD_LOCAL_GLOBALS);
|
InitOrDeinitGlobalVariables(INIT_THREAD_LOCAL_GLOBALS);
|
||||||
|
|||||||
@@ -29,13 +29,13 @@ public open class Throwable(open val message: String?, open val cause: Throwable
|
|||||||
getStackTraceStrings(stackTrace)
|
getStackTraceStrings(stackTrace)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getStackTrace(): Array<String> = stackTraceStrings
|
public fun getStackTrace(): Array<String> = stackTraceStrings
|
||||||
|
|
||||||
fun printStackTrace() {
|
public fun printStackTrace() {
|
||||||
println(this.toString())
|
println(this.toString())
|
||||||
|
|
||||||
for (element in stackTraceStrings) {
|
for (element in stackTraceStrings) {
|
||||||
println(" at " + element)
|
println(" at $element")
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cause?.printEnclosedStackTrace(this)
|
this.cause?.printEnclosedStackTrace(this)
|
||||||
@@ -48,7 +48,7 @@ public open class Throwable(open val message: String?, open val cause: Throwable
|
|||||||
this.printStackTrace()
|
this.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override public fun toString(): String {
|
||||||
val kClass = this::class
|
val kClass = this::class
|
||||||
val s = kClass.qualifiedName ?: kClass.simpleName ?: "Throwable"
|
val s = kClass.qualifiedName ?: kClass.simpleName ?: "Throwable"
|
||||||
return if (message != null) s + ": " + message.toString() else s
|
return if (message != null) s + ": " + message.toString() else s
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ if (MPPTools.isMacos() || MPPTools.isLinux()) {
|
|||||||
if (MPPTools.isMacos()) {
|
if (MPPTools.isMacos()) {
|
||||||
include ':objc'
|
include ':objc'
|
||||||
include ':opengl'
|
include ':opengl'
|
||||||
|
include ':symbolication'
|
||||||
include ':uikit'
|
include ':uikit'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Backtrace symbolication tool
|
||||||
|
|
||||||
|
Produces more verbose backtrace symbolication with file name and line number.
|
||||||
|
Only works on debug .dSYM binaries on macOS at the moment.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
plugins {
|
||||||
|
id 'kotlin-multiplatform'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine host preset.
|
||||||
|
def hostPreset = MPPTools.defaultHostPreset(project)
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
targets {
|
||||||
|
fromPreset(hostPreset, 'symbolication') {
|
||||||
|
compilations.main.outputKinds 'EXECUTABLE'
|
||||||
|
compilations.main.entryPoint 'symbolication.main'
|
||||||
|
compilations.main.cinterops {
|
||||||
|
coreSymbolication {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MPPTools.createRunTask(project, 'runProgram', kotlin.targets.symbolication) {
|
||||||
|
//args "./test.kexe.dSYM/Contents/Resources/DWARF/test.kexe"
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
kotlin.code.style=official
|
||||||
|
kotlin.import.noCommonSourceSets=true
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package = CoreSymbolication
|
||||||
|
linkerOpts.osx = -F /System/Library/PrivateFrameworks -framework CoreSymbolication
|
||||||
|
headerFilter = **
|
||||||
|
language=Objective-C
|
||||||
|
---
|
||||||
|
#include <CoreServices/CoreServices.h>
|
||||||
|
#include <mach/mach.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned long type;
|
||||||
|
void* contents;
|
||||||
|
} CSTypeRef;
|
||||||
|
|
||||||
|
typedef CSTypeRef CSSymbolicatorRef;
|
||||||
|
typedef CSTypeRef CSSymbolOwnerRef;
|
||||||
|
typedef CSTypeRef CSSymbolRef;
|
||||||
|
typedef CSTypeRef CSSourceInfoRef;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned long long location;
|
||||||
|
unsigned long long length;
|
||||||
|
} CSRange;
|
||||||
|
|
||||||
|
typedef unsigned long long CSArchitecture;
|
||||||
|
|
||||||
|
#define kCSNow LONG_MAX
|
||||||
|
|
||||||
|
cpu_type_t CSArchitectureGetCurrent();
|
||||||
|
|
||||||
|
CSSymbolicatorRef CSSymbolicatorCreateWithPid(pid_t pid);
|
||||||
|
|
||||||
|
CSSymbolicatorRef CSSymbolicatorCreateWithPathAndArchitecture(const char* path, cpu_type_t type);
|
||||||
|
|
||||||
|
CSArchitecture CSSymbolicatorGetArchitecture(CSSymbolicatorRef symbolicator);
|
||||||
|
|
||||||
|
CSSymbolOwnerRef CSSymbolicatorGetSymbolOwnerWithNameAtTime(
|
||||||
|
CSSymbolicatorRef symbolicator, const char* name, long time);
|
||||||
|
|
||||||
|
CSSymbolOwnerRef CSSymbolicatorGetSymbolOwnerWithAddressAtTime(
|
||||||
|
CSSymbolicatorRef symbolicator, unsigned long long address, long time);
|
||||||
|
|
||||||
|
CSSymbolOwnerRef CSSymbolicatorGetSymbolOwner(CSSymbolicatorRef cs);
|
||||||
|
|
||||||
|
CSSymbolRef CSSymbolicatorGetSymbolWithNameAtTime(
|
||||||
|
CSSymbolicatorRef symbolicator, const char* name, long time);
|
||||||
|
|
||||||
|
const char* CSSymbolOwnerGetName(CSSymbolOwnerRef owner);
|
||||||
|
|
||||||
|
unsigned long long CSSymbolOwnerGetBaseAddress(CSSymbolOwnerRef owner);
|
||||||
|
|
||||||
|
CSSourceInfoRef CSSymbolOwnerGetSourceInfoWithAddress(
|
||||||
|
CSSymbolOwnerRef owner, unsigned long long address);
|
||||||
|
|
||||||
|
const char* CSSymbolGetName(CSSymbolRef symbol);
|
||||||
|
|
||||||
|
CSRange CSSymbolGetRange(CSSymbolRef symbol);
|
||||||
|
|
||||||
|
const char* CSSourceInfoGetPath(CSSourceInfoRef info);
|
||||||
|
|
||||||
|
const char* CSSourceInfoGetFilename(CSSourceInfoRef info);
|
||||||
|
|
||||||
|
uint32_t CSSourceInfoGetLineNumber(CSSourceInfoRef info);
|
||||||
|
|
||||||
|
CSTypeRef CSRetain(CSTypeRef);
|
||||||
|
|
||||||
|
void CSRelease(CSTypeRef);
|
||||||
|
|
||||||
|
bool CSIsNull(CSTypeRef);
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package symbolication
|
||||||
|
|
||||||
|
import platform.darwin.*
|
||||||
|
|
||||||
|
import kotlinx.cinterop.*
|
||||||
|
import CoreSymbolication.*
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val program = if (args.size > 0 && args[0].isNotEmpty())
|
||||||
|
args[0] else throw Error("please specify .dSYM path as the first argument")
|
||||||
|
val arch = if (args.size > 1 && args[1].isNotEmpty()) args[1] else "current"
|
||||||
|
val input = generateSequence { readLine() }
|
||||||
|
analyzeTrace(program, arch, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun archToCpuName(arch: String): cpu_type_t = when (arch) {
|
||||||
|
"x64", "x86_64" -> CPU_TYPE_X86_64
|
||||||
|
"arm32" -> CPU_TYPE_ARM
|
||||||
|
"arm64" -> CPU_TYPE_ARM64
|
||||||
|
"current" -> CSArchitectureGetCurrent()
|
||||||
|
else -> TODO("unsupported $arch")
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
val owner = CSSymbolicatorGetSymbolOwner(symbolicator)
|
||||||
|
// Format is like
|
||||||
|
// at 14 test.kexe 0x0000000106a2e071 Konan_run_start + 113
|
||||||
|
val matcher = "(at \\d+\\s+\\S+\\s+0x[0-9a-f]+\\s+)([^+]+)\\+\\s(\\d+)".toRegex()
|
||||||
|
for (line in input) {
|
||||||
|
val match = matcher.find(line)
|
||||||
|
var result = line
|
||||||
|
if (match != null) {
|
||||||
|
val atPart = match.groupValues[1]
|
||||||
|
val functionName = match.groupValues[2].trim()
|
||||||
|
val offsetInFunction = match.groupValues[3].toUInt()
|
||||||
|
val symbol = CSSymbolicatorGetSymbolWithNameAtTime(symbolicator, functionName, kCSNow)
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println(result)
|
||||||
|
}
|
||||||
|
CSRelease(symbolicator)
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
fun f(p: Int) {
|
||||||
|
if (p == 0) throw Error()
|
||||||
|
f(p - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun g1(p: Int) {
|
||||||
|
if (p == 0) throw Error()
|
||||||
|
g2(p - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun g2(p: Int) {
|
||||||
|
g1(p - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
try {
|
||||||
|
f(10)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
g1(10)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user