Do not remove speculative frames in all cases.
If the first frame of an unwind is a totally invalid pc that's not in
any map, a speculative frame is added. Rather than deleting this frame
if no more unwinding is possible, leave it. This fixes a case where
the only frame you get is an invalid one, but the speculative frame
winds up in a shared library or somewhere else and gets removed.
Bug: 120505086
Test: New unit tests to catch this case pass.
Test: Verified original crashing program now emits two backtrace lines.
Change-Id: I088dff21c057386dcdaeb3fc2578b24322683bd0
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index b3c5549..792cd0b 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -239,8 +239,14 @@
if (!stepped) {
if (return_address_attempt) {
- // Remove the speculative frame.
- frames_.pop_back();
+ // Only remove the speculative frame if there are more than two frames
+ // or the pc in the first frame is in a valid map.
+ // This allows for a case where the code jumps into the middle of
+ // nowhere, but there is no other unwind information after that.
+ if (frames_.size() != 2 || maps_->Find(frames_[0].pc) != nullptr) {
+ // Remove the speculative frame.
+ frames_.pop_back();
+ }
break;
} else if (in_device_map) {
// Do not attempt any other unwinding, pc or sp is in a device