Skip to content

Commit d08a284

Browse files
authored
fix binary image extraction logic in tombstone parsing (#583)
1 parent e4fc66c commit d08a284

File tree

3 files changed

+100
-14
lines changed

3 files changed

+100
-14
lines changed

platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/reports/FatalIssueReporter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ internal class FatalIssueReporter(
152152
val lastReasonResult = latestAppExitInfoProvider.get(activityManager)
153153
if (lastReasonResult is LatestAppExitReasonResult.Valid) {
154154
val lastReason = lastReasonResult.applicationExitInfo
155-
lastReason.traceInputStream?.let {
155+
lastReason.traceInputStream?.use {
156156
mapToFatalIssueType(lastReason.reason)?.let { fatalIssueType ->
157157
fatalIssueReporterProcessor.persistAppExitReport(
158158
fatalIssueType = fatalIssueType,

platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/reports/processor/NativeCrashProcessor.kt

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import io.bitdrift.capture.reports.binformat.v1.Report
1717
import io.bitdrift.capture.reports.binformat.v1.ReportType
1818
import io.bitdrift.capture.reports.binformat.v1.Thread
1919
import io.bitdrift.capture.reports.binformat.v1.ThreadDetails
20-
import io.bitdrift.capture.reports.processor.ReportFrameBuilder.toOffset
2120
import java.io.InputStream
2221

2322
/**
@@ -48,32 +47,26 @@ internal object NativeCrashProcessor {
4847
val threadOffsets = mutableListOf<Int>()
4948
val binaryImageOffsets = mutableListOf<Int>()
5049

50+
val referencedBuildIds = mutableSetOf<String>()
51+
5152
tombstone.threadsMap.forEach { (tid, thread) ->
5253
val frameOffsets =
5354
thread.currentBacktraceList
5455
.map { frame ->
5556
val frameAddress = frame.pc.toULong()
56-
val functionOffset = frame.functionOffset.toULong()
5757
val isNativeFrame = frame.pc != 0L
5858
val imageId: String? = if (isNativeFrame) frame.buildId else null
5959

60-
if (isNativeFrame) {
61-
binaryImageOffsets.add(
62-
BinaryImage.createBinaryImage(
63-
builder,
64-
builder.toOffset(imageId),
65-
builder.toOffset(frame.fileName),
66-
frameAddress,
67-
),
68-
)
60+
if (!frame.buildId.isNullOrEmpty()) {
61+
referencedBuildIds.add(frame.buildId)
6962
}
63+
7064
val frameData =
7165
FrameData(
7266
symbolName = frame.functionName,
7367
fileName = if (!isNativeFrame) frame.fileName else null,
7468
imageId = imageId,
7569
frameAddress = frameAddress,
76-
symbolAddress = frameAddress - functionOffset,
7770
)
7871
ReportFrameBuilder.build(
7972
FrameType.AndroidNative,
@@ -107,6 +100,21 @@ internal object NativeCrashProcessor {
107100
ThreadDetails.createThreadsVector(builder, threadOffsets.toIntArray()),
108101
)
109102

103+
referencedBuildIds.forEach { buildId ->
104+
tombstone.memoryMappingsList
105+
.filter { it.buildId == buildId }
106+
.minByOrNull { it.beginAddress }
107+
?.let {
108+
binaryImageOffsets.add(
109+
BinaryImage.createBinaryImage(
110+
builder,
111+
builder.createString(buildId),
112+
builder.createString(it.mappingName),
113+
it.beginAddress.toULong(),
114+
),
115+
)
116+
}
117+
}
110118
return Report.createReport(
111119
builder,
112120
sdk,
@@ -130,7 +138,9 @@ internal object NativeCrashProcessor {
130138
builder.createString(signalName.ifEmpty { description })
131139
val causeText =
132140
tombstone.causesList.firstOrNull()?.humanReadable
133-
?: tombstone.abortMessage.ifEmpty { signalDescriptions[signalName] ?: "Native crash" }
141+
?: tombstone.abortMessage.ifEmpty {
142+
signalDescriptions[signalName] ?: "Native crash"
143+
}
134144
val cause = builder.createString(causeText)
135145
return Error.createError(
136146
builder,
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// capture-sdk - bitdrift's client SDK
2+
// Copyright Bitdrift, Inc. All rights reserved.
3+
//
4+
// Use of this source code is governed by a source available license that can be found in the
5+
// LICENSE file or at:
6+
// https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt
7+
8+
package io.bitdrift.capture.reports.processor
9+
10+
import com.google.flatbuffers.FlatBufferBuilder
11+
import io.bitdrift.capture.TombstoneProtos
12+
import io.bitdrift.capture.reports.binformat.v1.Report
13+
import org.assertj.core.api.Assertions.assertThat
14+
import org.junit.Test
15+
import java.io.ByteArrayInputStream
16+
import java.io.ByteArrayOutputStream
17+
18+
class NativeCrashProcessorTest {
19+
@Test
20+
fun `dedupes by build-id and picks the lowest address memory map for report`() {
21+
val tombstone =
22+
TombstoneProtos.Tombstone
23+
.newBuilder()
24+
.setTid(1)
25+
.also {
26+
it.putThreads(
27+
1,
28+
TombstoneProtos.Thread
29+
.newBuilder()
30+
.setId(1)
31+
.addCurrentBacktrace(
32+
TombstoneProtos.BacktraceFrame
33+
.newBuilder()
34+
.setBuildId("build-id"),
35+
).build(),
36+
)
37+
38+
it.addMemoryMappings(
39+
TombstoneProtos.MemoryMapping
40+
.newBuilder()
41+
.setBuildId("build-id")
42+
.setBeginAddress(200),
43+
)
44+
it.addMemoryMappings(
45+
TombstoneProtos.MemoryMapping
46+
.newBuilder()
47+
.setBuildId("build-id")
48+
.setBeginAddress(150),
49+
)
50+
it.addMemoryMappings(
51+
TombstoneProtos.MemoryMapping
52+
.newBuilder()
53+
.setBuildId("build-id")
54+
.setBeginAddress(100),
55+
)
56+
}.build()
57+
58+
val report = makeReport(tombstone)
59+
60+
assertThat(report.binaryImagesLength).isEqualTo(1)
61+
assertThat(report.binaryImages(0)?.loadAddress).isEqualTo(100.toULong())
62+
}
63+
64+
fun makeReport(tombstone: TombstoneProtos.Tombstone): Report {
65+
val out = ByteArrayOutputStream()
66+
tombstone.writeTo(out)
67+
val tombstone = ByteArrayInputStream(out.toByteArray())
68+
69+
val flatBufferBuilder = FlatBufferBuilder()
70+
val reportOffset = NativeCrashProcessor.process(flatBufferBuilder, 0, 0, 0, "description", tombstone)
71+
72+
flatBufferBuilder.finish(reportOffset)
73+
74+
return Report.getRootAsReport(flatBufferBuilder.dataBuffer())
75+
}
76+
}

0 commit comments

Comments
 (0)