Skip to content

Commit 36eea2b

Browse files
author
Lauri Alanko
committed
Add addr_mode attributes to ANR stack frames
The instruction addresses of native stack frames in thread dumps are relative to the image file from which the code is loaded, and there are no absolute mapping addresses of images available. So explicitly inform the Sentry server about the correct images by using a relative "addr_mode" attribute. Also add the attribute to the SentryStackFrame class since it was not yet supported by it. The field documentation is converted from event.schema.json in the sentry server repo.
1 parent 1d814c2 commit 36eea2b

File tree

6 files changed

+83
-45
lines changed

6 files changed

+83
-45
lines changed

sentry-android-core/src/main/java/io/sentry/android/core/internal/threaddump/ThreadDumpParser.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ private SentryStackTrace parseStacktrace(
261261
debugImage.setCodeId(buildId);
262262
debugImages.put(debugId, debugImage);
263263
}
264+
// The addresses in the thread dump are relative to the image
265+
frame.setAddrMode("rel:" + debugId);
264266
}
265267

266268
frames.add(frame);

sentry-android-core/src/test/java/io/sentry/android/core/AnrV2IntegrationTest.kt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -305,14 +305,15 @@ class AnrV2IntegrationTest {
305305
)
306306
assertEquals("__start_thread", firstFrame.function)
307307
assertEquals(64, firstFrame.lineno)
308-
assertEquals("0x00000000000530b8", firstFrame.instructionAddr)
309-
assertEquals("native", firstFrame.platform)
310-
311-
val image = it.debugMeta?.images?.find {
312-
it.debugId == "741f3301-bbb0-b92c-58bd-c15282b8ec7b"
313-
}
314-
assertNotNull(image)
315-
assertEquals("/apex/com.android.runtime/lib64/bionic/libc.so", image.codeFile)
308+
assertEquals("0x00000000000530b8", firstFrame.instructionAddr)
309+
assertEquals("native", firstFrame.platform)
310+
assertEquals("rel:741f3301-bbb0-b92c-58bd-c15282b8ec7b", firstFrame.addrMode)
311+
312+
val image = it.debugMeta?.images?.find {
313+
it.debugId == "741f3301-bbb0-b92c-58bd-c15282b8ec7b"
314+
}
315+
assertNotNull(image)
316+
assertEquals("/apex/com.android.runtime/lib64/bionic/libc.so", image.codeFile)
316317
},
317318
argThat<Hint> {
318319
val hint = HintUtils.getSentrySdkHint(this)

sentry-android-core/src/test/java/io/sentry/android/core/internal/threaddump/ThreadDumpParserTest.kt

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -116,43 +116,47 @@ class ThreadDumpParserTest {
116116
assertEquals("syscall", lastFrame.function)
117117
assertEquals(28, lastFrame.lineno)
118118
assertNull(lastFrame.isInApp)
119-
assertEquals("0x000000000004c35c", lastFrame.instructionAddr)
120-
assertEquals("native", lastFrame.platform)
121-
122-
val nosymFrame = frames.get(21)
123-
assertEquals("/apex/com.android.art/javalib/core-oj.jar", nosymFrame.`package`)
124-
assertNull(nosymFrame.function)
125-
assertNull(nosymFrame.lineno)
126-
assertEquals("0x00000000000ec474", nosymFrame.instructionAddr)
127-
128-
val spaceFrame = frames.get(14)
129-
assertEquals(
130-
"[anon:dalvik-classes16.dex extracted in memory from /data/app/~~izn1xSZpFlzfVmWi_I0xlQ=="
131-
+ "/io.sentry.samples.android-tQSGMNiGA-qdjZm6lPOcNw==/base.apk!classes16.dex]",
132-
spaceFrame.`package`)
133-
assertNull(spaceFrame.function)
134-
assertNull(spaceFrame.lineno)
135-
assertEquals("0x00000000000306f0", spaceFrame.instructionAddr)
136-
137-
val offsetFrame = frames.get(145)
138-
assertEquals("/system/framework/framework.jar (offset 0x12c2000)", offsetFrame.`package`)
139-
assertNull(offsetFrame.function)
140-
assertNull(offsetFrame.lineno)
141-
assertEquals("0x00000000002c8e18", offsetFrame.instructionAddr)
142-
assertNull(offsetFrame.addrMode)
143-
144-
val deletedFrame = frames.get(117)
145-
assertEquals("/memfd:jit-cache (deleted) (offset 0x2000000)", deletedFrame.`package`)
146-
assertEquals("kotlinx.coroutines.DispatchedTask.run", deletedFrame.function)
147-
assertEquals(1816, deletedFrame.lineno)
148-
assertEquals("0x00000000020b89d8", deletedFrame.instructionAddr)
149-
150-
val debugImages = parser.debugImages
151-
val image = debugImages["499d48ba-c085-17cf-3209-da67405662f9"]
152-
assertNotNull(image)
153-
assertEquals("499d48ba-c085-17cf-3209-da67405662f9", image.debugId)
154-
assertEquals("/apex/com.android.runtime/lib64/bionic/libc.so", image.codeFile)
155-
assertEquals("ba489d4985c0cf173209da67405662f9", image.codeId)
119+
assertEquals("0x000000000004c35c", lastFrame.instructionAddr)
120+
assertEquals("rel:499d48ba-c085-17cf-3209-da67405662f9", lastFrame.addrMode)
121+
assertEquals("native", lastFrame.platform)
122+
123+
val nosymFrame = frames.get(21)
124+
assertEquals("/apex/com.android.art/javalib/core-oj.jar", nosymFrame.`package`)
125+
assertNull(nosymFrame.function)
126+
assertNull(nosymFrame.lineno)
127+
assertEquals("0x00000000000ec474", nosymFrame.instructionAddr)
128+
assertNull(nosymFrame.addrMode)
129+
130+
val spaceFrame = frames.get(14)
131+
assertEquals(
132+
"[anon:dalvik-classes16.dex extracted in memory from /data/app/~~izn1xSZpFlzfVmWi_I0xlQ=="
133+
+ "/io.sentry.samples.android-tQSGMNiGA-qdjZm6lPOcNw==/base.apk!classes16.dex]",
134+
spaceFrame.`package`)
135+
assertNull(spaceFrame.function)
136+
assertNull(spaceFrame.lineno)
137+
assertEquals("0x00000000000306f0", spaceFrame.instructionAddr)
138+
assertNull(spaceFrame.addrMode)
139+
140+
val offsetFrame = frames.get(145)
141+
assertEquals("/system/framework/framework.jar (offset 0x12c2000)", offsetFrame.`package`)
142+
assertNull(offsetFrame.function)
143+
assertNull(offsetFrame.lineno)
144+
assertEquals("0x00000000002c8e18", offsetFrame.instructionAddr)
145+
assertNull(offsetFrame.addrMode)
146+
147+
val deletedFrame = frames.get(117)
148+
assertEquals("/memfd:jit-cache (deleted) (offset 0x2000000)", deletedFrame.`package`)
149+
assertEquals("kotlinx.coroutines.DispatchedTask.run", deletedFrame.function)
150+
assertEquals(1816, deletedFrame.lineno)
151+
assertEquals("0x00000000020b89d8", deletedFrame.instructionAddr)
152+
assertNull(deletedFrame.addrMode)
153+
154+
val debugImages = parser.debugImages
155+
val image = debugImages["499d48ba-c085-17cf-3209-da67405662f9"]
156+
assertNotNull(image)
157+
assertEquals("499d48ba-c085-17cf-3209-da67405662f9", image.debugId)
158+
assertEquals("/apex/com.android.runtime/lib64/bionic/libc.so", image.codeFile)
159+
assertEquals("ba489d4985c0cf173209da67405662f9", image.codeId)
156160
}
157161

158162
@Test

sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,20 @@ public final class SentryStackFrame implements JsonUnknown, JsonSerializable {
9393
* take place.
9494
*/
9595
private @Nullable String instructionAddr;
96+
/**
97+
* Defines the addressing mode for addresses.
98+
*
99+
* <p>This can be:
100+
*
101+
* <ul>
102+
* <li><code>"abs"</code> (the default): <code>instruction_addr</code> is absolute.
103+
* <li><code>"rel:$idx"</code>: <code>instruction_addr</code> is relative to the
104+
* <code>debug_meta.image</code> identified by its index in the list.
105+
* <li><code>"rel:$uuid"</code>: <code>instruction_addr</code> is relative to the
106+
* <code>debug_meta.image</code> identified by its <code>debug_id</code>.
107+
* </ul>
108+
*/
109+
private @Nullable String addrMode;
96110

97111
/**
98112
* Potentially mangled name of the symbol as it appears in an executable.
@@ -263,6 +277,14 @@ public void setInstructionAddr(final @Nullable String instructionAddr) {
263277
this.instructionAddr = instructionAddr;
264278
}
265279

280+
public @Nullable String getAddrMode() {
281+
return addrMode;
282+
}
283+
284+
public void setAddrMode(final @Nullable String addrMode) {
285+
this.addrMode = addrMode;
286+
}
287+
266288
public @Nullable Boolean isNative() {
267289
return _native;
268290
}
@@ -325,6 +347,7 @@ public static final class JsonKeys {
325347
public static final String IMAGE_ADDR = "image_addr";
326348
public static final String SYMBOL_ADDR = "symbol_addr";
327349
public static final String INSTRUCTION_ADDR = "instruction_addr";
350+
public static final String ADDR_MODE = "addr_mode";
328351
public static final String RAW_FUNCTION = "raw_function";
329352
public static final String SYMBOL = "symbol";
330353
public static final String LOCK = "lock";
@@ -376,6 +399,9 @@ public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger
376399
if (instructionAddr != null) {
377400
writer.name(JsonKeys.INSTRUCTION_ADDR).value(instructionAddr);
378401
}
402+
if (addrMode != null) {
403+
writer.name(JsonKeys.ADDR_MODE).value(addrMode);
404+
}
379405
if (rawFunction != null) {
380406
writer.name(JsonKeys.RAW_FUNCTION).value(rawFunction);
381407
}
@@ -447,6 +473,9 @@ public static final class Deserializer implements JsonDeserializer<SentryStackFr
447473
case JsonKeys.INSTRUCTION_ADDR:
448474
sentryStackFrame.instructionAddr = reader.nextStringOrNull();
449475
break;
476+
case JsonKeys.ADDR_MODE:
477+
sentryStackFrame.addrMode = reader.nextStringOrNull();
478+
break;
450479
case JsonKeys.RAW_FUNCTION:
451480
sentryStackFrame.rawFunction = reader.nextStringOrNull();
452481
break;

sentry/src/test/java/io/sentry/protocol/SentryStackFrameSerializationTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class SentryStackFrameSerializationTest {
3232
imageAddr = "27ec1be5-e8a1-485c-b020-f4d9f80a6624"
3333
symbolAddr = "180e12cd-1fa8-405d-8dd8-e87b33fa2eb0"
3434
instructionAddr = "19864a78-2466-461f-9f0b-93a5c9ae7622"
35+
addrMode = "49d415f3-1be5-422c-b877-b82b4e4c2990"
3536
rawFunction = "f33035a4-0cf0-453d-b6f4-d7c27e9af924"
3637
symbol = "d9807ffe-d517-11ed-afa1-0242ac120002"
3738
lock = SentryLockReason().apply {

sentry/src/test/resources/json/sentry_stack_frame.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"image_addr": "27ec1be5-e8a1-485c-b020-f4d9f80a6624",
1414
"symbol_addr": "180e12cd-1fa8-405d-8dd8-e87b33fa2eb0",
1515
"instruction_addr": "19864a78-2466-461f-9f0b-93a5c9ae7622",
16+
"addr_mode": "49d415f3-1be5-422c-b877-b82b4e4c2990",
1617
"raw_function": "f33035a4-0cf0-453d-b6f4-d7c27e9af924",
1718
"symbol": "d9807ffe-d517-11ed-afa1-0242ac120002",
1819
"lock": {

0 commit comments

Comments
 (0)