Skip to content

Commit 95bd726

Browse files
committed
move instructionAddressAdjustment to SentryStackTrace
1 parent 4b6e1fb commit 95bd726

File tree

2 files changed

+51
-22
lines changed

2 files changed

+51
-22
lines changed

sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,15 @@ private List<SentryThread> createThreads(
6060
List<SentryThread> threads = new ArrayList<>();
6161
for (Map.Entry<Integer, TombstoneProtos.Thread> threadEntry :
6262
tombstone.getThreadsMap().entrySet()) {
63+
TombstoneProtos.Thread threadEntryValue = threadEntry.getValue();
6364

6465
SentryThread thread = new SentryThread();
6566
thread.setId(Long.valueOf(threadEntry.getKey()));
66-
thread.setName(threadEntry.getValue().getName());
67+
thread.setName(threadEntryValue.getName());
6768

68-
SentryStackTrace stacktrace = createStackTrace(threadEntry);
69+
SentryStackTrace stacktrace = createStackTrace(threadEntryValue);
6970
thread.setStacktrace(stacktrace);
70-
if (tombstone.getTid() == threadEntry.getValue().getId()) {
71+
if (tombstone.getTid() == threadEntryValue.getId()) {
7172
thread.setCrashed(true);
7273
// even though we refer to the thread_id from the exception,
7374
// the backend currently requires a stack-trace in exception
@@ -80,11 +81,10 @@ private List<SentryThread> createThreads(
8081
}
8182

8283
@NonNull
83-
private static SentryStackTrace createStackTrace(
84-
Map.Entry<Integer, TombstoneProtos.Thread> threadEntry) {
84+
private static SentryStackTrace createStackTrace(TombstoneProtos.Thread thread) {
8585
List<SentryStackFrame> frames = new ArrayList<>();
8686

87-
for (TombstoneProtos.BacktraceFrame frame : threadEntry.getValue().getCurrentBacktraceList()) {
87+
for (TombstoneProtos.BacktraceFrame frame : thread.getCurrentBacktraceList()) {
8888
SentryStackFrame stackFrame = new SentryStackFrame();
8989
stackFrame.setPackage(frame.getFileName());
9090
stackFrame.setFunction(frame.getFunctionName());
@@ -95,15 +95,13 @@ private static SentryStackTrace createStackTrace(
9595
SentryStackTrace stacktrace = new SentryStackTrace();
9696
stacktrace.setFrames(frames);
9797

98-
Map<String, Object> unknown = new HashMap<>();
9998
// `libunwindstack` used for tombstones already applies instruction address adjustment:
10099
// https://android.googlesource.com/platform/system/unwinding/+/refs/heads/main/libunwindstack/Regs.cpp#175
101100
// prevent "processing" from doing it again.
102-
unknown.put("instruction_addr_adjustment", "none");
103-
stacktrace.setUnknown(unknown);
101+
stacktrace.setInstructionAddressAdjustment("none");
104102

105103
Map<String, String> registers = new HashMap<>();
106-
for (TombstoneProtos.Register register : threadEntry.getValue().getRegistersList()) {
104+
for (TombstoneProtos.Register register : thread.getRegistersList()) {
107105
registers.put(register.getName(), String.format("0x%x", register.getU64()));
108106
}
109107
stacktrace.setRegisters(registers);
@@ -113,14 +111,16 @@ private static SentryStackTrace createStackTrace(
113111

114112
@NonNull
115113
private List<SentryException> createException(TombstoneProtos.Tombstone tombstone) {
116-
TombstoneProtos.Signal signalInfo = tombstone.getSignalInfo();
117-
118114
SentryException exception = new SentryException();
119-
exception.setType(signalInfo.getName());
120-
exception.setValue(excTypeValueMap.get(signalInfo.getName()));
121-
exception.setMechanism(createMechanismFromSignalInfo(signalInfo));
122-
exception.setThreadId((long) tombstone.getTid());
123115

116+
if (tombstone.hasSignalInfo()) {
117+
TombstoneProtos.Signal signalInfo = tombstone.getSignalInfo();
118+
exception.setType(signalInfo.getName());
119+
exception.setValue(excTypeValueMap.get(signalInfo.getName()));
120+
exception.setMechanism(createMechanismFromSignalInfo(signalInfo));
121+
}
122+
123+
exception.setThreadId((long) tombstone.getTid());
124124
List<SentryException> exceptions = new ArrayList<>(1);
125125
exceptions.add(exception);
126126

@@ -129,18 +129,23 @@ private List<SentryException> createException(TombstoneProtos.Tombstone tombston
129129

130130
@NonNull
131131
private static Mechanism createMechanismFromSignalInfo(TombstoneProtos.Signal signalInfo) {
132-
Map<String, Object> meta = new HashMap<>();
133-
meta.put("number", signalInfo.getNumber());
134-
meta.put("name", signalInfo.getName());
135-
meta.put("code", signalInfo.getCode());
136-
meta.put("code_name", signalInfo.getCodeName());
137132

138133
Mechanism mechanism = new Mechanism();
139134
// this follows the current processing triggers strictly, changing any of these
140135
// alters grouping and name (long-term we might want to have a tombstone mechanism)
136+
// TODO: if we align this with ANRv2 this would be overwritten in a BackfillingEventProcessor as
137+
// `ApplicationExitInfo` not sure what the right call is. `ApplicationExitInfo` is certainly correct. But `signalhandler` isn't
138+
// wrong either, since all native crashes retrieved via `REASON_CRASH_NATIVE` will be signals. I am not sure what the side-effect
139+
// in ingestion/processing will be if we change the mechanism, but initially i wanted to stay close to the Native SDK.
141140
mechanism.setType("signalhandler");
142141
mechanism.setHandled(false);
143142
mechanism.setSynthetic(true);
143+
144+
Map<String, Object> meta = new HashMap<>();
145+
meta.put("number", signalInfo.getNumber());
146+
meta.put("name", signalInfo.getName());
147+
meta.put("code", signalInfo.getCode());
148+
meta.put("code_name", signalInfo.getCodeName());
144149
mechanism.setMeta(meta);
145150

146151
return mechanism;
@@ -154,7 +159,7 @@ private Message constructMessage(TombstoneProtos.Tombstone tombstone) {
154159
// reproduce the message `debuggerd` would use to dump the stack trace in logcat
155160
message.setFormatted(
156161
String.format(
157-
Locale.getDefault(),
162+
Locale.ROOT,
158163
"Fatal signal %s (%d), %s (%d), pid = %d (%s)",
159164
signalInfo.getName(),
160165
signalInfo.getNumber(),

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@ public final class SentryStackTrace implements JsonUnknown, JsonSerializable {
6666
*/
6767
private @Nullable Boolean snapshot;
6868

69+
/**
70+
* This value indicates if, and how, `instruction_addr` values in the stack frames need to be adjusted before they are symbolicated.
71+
* TODO: should we make this an enum or is a string value fine?
72+
*
73+
* @see SentryStackFrame#getInstructionAddr()
74+
* @see SentryStackFrame#setInstructionAddr(String)
75+
*/
76+
private @Nullable String instructionAddressAdjustment;
77+
6978
@SuppressWarnings("unused")
7079
private @Nullable Map<String, Object> unknown;
7180

@@ -122,10 +131,19 @@ public void setUnknown(@Nullable Map<String, Object> unknown) {
122131
this.unknown = unknown;
123132
}
124133

134+
public @Nullable String getInstructionAddressAdjustment() {
135+
return instructionAddressAdjustment;
136+
}
137+
138+
public void setInstructionAddressAdjustment(@Nullable String instructionAddressAdjustment) {
139+
this.instructionAddressAdjustment = instructionAddressAdjustment;
140+
}
141+
125142
public static final class JsonKeys {
126143
public static final String FRAMES = "frames";
127144
public static final String REGISTERS = "registers";
128145
public static final String SNAPSHOT = "snapshot";
146+
public static final String INSTRUCTION_ADDRESS_ADJUSTMENT = "instruction_add_adjustment";
129147
}
130148

131149
@Override
@@ -141,6 +159,9 @@ public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger
141159
if (snapshot != null) {
142160
writer.name(JsonKeys.SNAPSHOT).value(snapshot);
143161
}
162+
if (instructionAddressAdjustment != null) {
163+
writer.name(JsonKeys.INSTRUCTION_ADDRESS_ADJUSTMENT).value(instructionAddressAdjustment);
164+
}
144165
if (unknown != null) {
145166
for (String key : unknown.keySet()) {
146167
Object value = unknown.get(key);
@@ -174,6 +195,9 @@ public static final class Deserializer implements JsonDeserializer<SentryStackTr
174195
case JsonKeys.SNAPSHOT:
175196
sentryStackTrace.snapshot = reader.nextBooleanOrNull();
176197
break;
198+
case JsonKeys.INSTRUCTION_ADDRESS_ADJUSTMENT:
199+
sentryStackTrace.instructionAddressAdjustment = reader.nextStringOrNull();
200+
break;
177201
default:
178202
if (unknown == null) {
179203
unknown = new ConcurrentHashMap<>();

0 commit comments

Comments
 (0)